7

I have a class that is responsible for performing conversions from/to twenty-something types. Let's call this class ConvertUtils.

For C# programmers out there - this class expands .Net's Convert class.

It looks something like this:

public static class ConvertUtils {
    public static object ChangeType(object obj, Type newType) {
        if (conversionSupportedByFramework)
            return Convert.ChangeType(obj, newType);
        else
            ConvertSpecialCases(obj, newType);
    }
}

How would you go about testing it? I'm assuming we do need to black-box test this code.

The two ways we thought about, are:

  1. Writing 400+ unit tests - cover all to/from combinations that we can think of.
  2. Write tests only for the new conversions - the ones not supported by the Convert class - actually testing only the ConvertSpecialCases() function [which isn't our goal, as stated above]

The con of the first possibility is to have too many tests - which prolongs the build time, involves maintaining more code, etc.

The con of the second possibility is to not fully check the responsibility of the class - what if a certain if statement decides to implement (wrong) custom logic, instead of letting Convert do it's job? e.g. just before if (conversionSupportedByFramework) someone decides to call some custom logic?

What do you think about this issue?

toniedzwiedz
  • 1,353
Berlo
  • 127

4 Answers4

4

This depends on how your conversion class looks like. If it looks like this:

  class MyConvert
  {
       public static Foo1 ToFoo1(Bar1 bar){...}
       public static Foo2 ToFoo2(Bar1 bar){...}
       public static Foo3 ToFoo3(Bar1 bar){...}
       // ...
       public static Foo1 ToFoo1(Bar2 bar){...}
       public static Foo2 ToFoo2(Bar2 bar){...}
       // ...
       public static Foo20 ToFoo20(Bar20 bar){...}
  }

you should implement at least one test (better two or three) for each method. And if you have 400 methods, you need a small multiple of 400 tests.

If, however, your class looks different, and you have something like an "internal representation class" for all of your Bar objects, you can reduce the number of tests. Assume something like this:

  class MyConvert
  {
       public static Foo1 ToFoo1(object bar)
       {
           MyInternalObj myObj = new MyInternalObj(bar);
           return myObj.ToFoo1();
       }
       public static Foo2 ToFoo2(object bar)
       {
           MyInternalObj myObj = new MyInternalObj(bar);
           return myObj.ToFoo2();
       }
      // ...
  }

you will only have to write tests for the constructor of MyInternalObj for all allowed type of objects (at least 20), and additional tests for the methods ToFoo1, ToFoo2,..., of MyInternalObj (also at least 20, or a small multiple of those).

Knowing your implementation looks like this, but you do not want to access MyInternalObj directly, you can also apply the same tests by calling MyConvert.ToFoo1 with 20 different Bar types, and MyConvert.ToFooXYZ in all 20 variations using the same "Bar" type.

Or more general: make sure you get a good code and branch coverage of all the code you have written.

Doc Brown
  • 218,378
4

You don't have to test .NET Framework's code in your specific case, because:

  • You can't inherit from Convert class, since this class is static; even if you could do that, for example if Convert class weren't static:

  • The Convert class has no virtual methods,

  • There are no instance methods,

  • There are no abstract methods,

  • You cannot override static methods in a class,

  • You shouldn't hide methods by using new keyword anyway (and if you do, Code analysis will shout at you).

The only way you may be able to screw with existent functionality is through Reflection. If you use Reflection in order to play with the internals of the Convert class, then yes, you have to study and test the impact it may have.

Otherwise, you just have to test the new code you'll write in your custom class.

2

The fact that your class is a conversion class, the fact that it is static, and the fact that it expands an existing framework class are all irrelevant. This question is an instance of the more general question of black-box vs. white-box testing.

In lack of any very good reason to perform white-box testing, all testing should be black-box testing.

This means that your testing code should not be making any assumptions about the internals of the system-under-test.

This in turn means that your testing code should not assume that your conversion class delegates to some other conversion class. (Precisely because it may delegate, and then again who knows, it might not delegate.) So, testing the entire public interface of your conversion class is the way to go.

That having been said, let me add that since you are writing a static class which expands on the functionality of another static class, the way to reduce your testing code is by expressly refraining from duplicating the functionality of the existing framework class. If you want one of the conversions provided by the framework class, invoke the framework class. If you want one of the conversions provided by your class, invoke your class. There is no reason to wrap the functionality of a static framework class inside a static custom class, there is not even any real wrapping going on, only pretending, because the functionality of the framework class is still publicly available to any piece of code that wishes to invoke it.

Mike Nakis
  • 32,803
0

Firstly, determine whether your changes will impact other public methods from the Convert class. If they will, find out which ones are impacted. Now you are better equipped to make a decision.

In case there is no impact in other public methods and functionalities, then only focus on new things you add or the ones you change.

If the change affects other areas of the Converter class, start testing what you have added or changed, then test methods your modifications have impacted.

Another advice is, if your changes affect existing features, when testing existing features give priority to the ones you are already using. Probably they will not be a big number.

Something else to consider is the following. For methods that have not changed, use the original Converter class. Use your new one only for the changing elements. When you are sure that your new Converter class is working, then make all modifications. Even if you use a lot of these Converter methods, making the change will not be too hard because the method signatures will not change and since you are confident the new Converter is working, your software should have no impact.