Recommendations for unitating techniques that contain conditionals

I am new to unittesting and am currently having trouble finding a decent way to test methods containing branches.

I created a small demo method which I hope can 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 enter a list of accounts that are empty and non-empty in the same test, or should I have separate tests?

Also my ExportNonEmpty () and ExportEmpty () methods are private, but write files to the file system. Do I have to supply a mock FileProvider to keep the file system from touching?

Do I have to export ExportNonEmpty () and ExportEmpty () to be able to test them separately? These methods also contain multiple if-then-else statements and can throw exceptions and more.

I find if I create a test for each codogram, I have the code to copy from one test to another - generating mocks, etc., is that a little weird?

Do I have to expose the counter variables as external variables to test them after the method call?

this.GetOUtputPath () fetches values ​​from a config file via the ConfigurationManager, which is static. Should I a) mock this either by creating a partial mock for the class in testt and overwrite the GetOutputPath method, or b) Create a custom config adapter that can be mocked?

I am using nunit and Rhino Mocks.

+1


source to share


2 answers


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

As for checking the result: setting and testing the counters will give a "white box" test, when the test knows about the internal state of the object, this gives a more thorough test, but makes it difficult to change the implementation later. (If you change the implementation, the test may fail even if the effects are the same.)



My preference usually checks the black box and only checks the external consequences of the operation. Then you can change the internal structure and regression test if the open functionality remains the same. However, this may require much more layout coding.

There are quite a few libraries for java that can help you build mock objects, I don't know about .net, but I would guess it is.

+1


source


Separate tests for each condition. I am assuming that you trust foreach to iterate over a loop containing both. I would. Presumably you are testing a method where you mock elsewhere to make sure it correctly returns both types of accounts, if any.

Instead of copying the code, you can refactor by extracting the shared code into the methods of your test class, or even the TestHelper class. Parameterize them, if necessary, to make them public.

You should be able to test your private methods by adding an accessory to the class under test. One will be added automatically if you use the Create Units item by right clicking in a private method, or just add the private method as one to create a unit test to add for the whole class. For testing ExportAccounts, just use data that you know will not throw exceptions so you can test both direct logic and exception handling.



I would not expose method variables. They are not needed outside of the method. However, you should mock the log to make sure it is called with the expected parameters.

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

EDIT: For a basic reading in unit testing, I would recommend Pragmatic Device Testing (C # version) and the unit testing chapter in Code is complete . You can also choose Test Driven Development in .Net , but others are more general.

+1


source







All Articles