views:

166

answers:

2

I am new to unittesting and currently have a problem with finding a decent way to test methods that contain branches.

I created a small demo method I hope could be used to explain the problem.

public void ExportAccounts()
{
     int emptyAccounts = 0;
     int nonEmptyAccounts = 0;
     int errorous = 0;
     string outputPath = this.GetOutputPath();
     Account[] accounts = this.MyWebserviceAdapter.GetAccounts();
     foreach(Account account in accounts)
     {
        try 
        {
          if(account.Amount > 0)
          {
               this.ExportNonEmpty(outputPath, account);
               nonEmptyAccounts++;
          } else {
               this.ExportEmptyAccount(outputPath, account);
               emptyAccounts++;
          }
        } catch(Exception e) {
          logger.error(e);
          errorous++;
        }
     }
     logger.debug(string.Format("{0} empty / {1} non empty / {2} errorous", emptyAccounts, nonEmptyAccounts, errorous));
}

I can mock MyWebserviceAdapter to return a predefined list of accounts. Should I input a list of accounts that are empty and nonempty in the same test or should I have separate tests?

Also my ExportNonEmpty() and ExportEmpty() methods are private but do write files to the filesystem. Should I supply a mock FileProvider so that the filesystem is not being touched?

Should I expose ExportNonEmpty() and ExportEmpty() to be able to test those separately? Those methods also contain a few if-then-else statements and can throw exceptions and whatnot.

I find if I create a test for every codepath I have copy code from one test to another - generating mocks etc. .. isnt that a bit odd?

Should I expose the counter variables as out variables to be able to verify them after calling the method?

this.GetOUtputPath() fetches values from the configuration file through ConfigurationManager which is static. Should I a) mock this out either by creating a partial mock for the class under testt and overwrite the GetOutputPath method or b) Create my own ConfigurationAdapter that can be mocked out?

I am using nunit and Rhino Mocks.

+1  A: 

I would test this with several test-vectors: all-empty, all-non-empty, and mixed starting and ending with both empty and non-empty.

As for verifying the result: exposing and testing the counters would give a «white box» test, where the test is aware of the internal state of the object, this gives a more thorough test, but makes it more difficult to change the implementation later. (If you change the implementation, the test might fail even if the effects are the same).

My preference is usually to test «black box», and only test the externally observable consequences of the operation. Then you can change the internal structure and regression-test if the exposed functionality is still the same. However, this might need much more mock-coding.

For java there are quite a few libraries which can help you construct mock-objects, I don't know about .net, but I would assume the same to be the case.

Rolf Rander
Would you then have a separate test method for each of the test vectors? Doing so would ensue that a lot of the mocking would have to be copied to each of the testing methods I presume. Can you comment on how you would do this?
Fadeproof
+1  A: 

Separate tests for each condition. I assume that you trust foreach to iterate over a loop containing both. I would. Presumably you are testing the method you are mocking elsewhere to ensure that it properly returns both types of accounts when present.

Instead of copying code, you could refactor by extracting common code into methods in your test class or even into a TestHelper class. Parameterize them if need be to make them generally usable.

You should be able to test your private methods by adding an accessor for the class under test. One will be added automatically if you use the "Create Unit Tests" right-click menu item while in the private method or simply add the private method as one to create a unit test for when adding for the whole class. For testing ExportAccounts just use data that you know will and will not throw exceptions so that you can test both the straight-line logic and the exception handling.

I wouldn't expose the method variables. They are not needed outside the method. You should however mock the logger to make sure that it is called with the expected parameters.

Create the ConfigurationAdapter (or Wrapper) and inject it into your class to remove the dependency on the static class. Mock out the adapter or provide a fake implementation, your choice. Removing the dependency is a good pattern to follow anyway. I prefer not to mock or stub anything in the class under test.

EDIT: For basic reading on Unit Testing I would recommend Pragmatic Unit Testing (C# version) and the chapter on unit testing in Code Complete. You might also want to pick up Test Driven Development in .Net, but the others are more general.

tvanfosson
You mention extracting common code which I agree would be a good idea - but the problem is with mocks that you are injecting can not be extracted as I am setting up expected calls to it in every test method hence all the copying if testing different conditions in different test methods.
Fadeproof
Yes, but your expectations should be very similar with many differing only by what values are expected. Pass these values in as parameters to the extracted method. I know this works -- I do it regularly. Return the mocked/stubbed objects and set up additional stubs/expectations as needed.
tvanfosson
can you show me an example of how this would be done as I'm a bit confused on how this should be done?
Fadeproof