views:

105

answers:

4

I have a method in a class for which they are a few different outcomes (based upon event responses etc). But this is a single atomic function which is to used by other applications.

I have broken down the main blocks of the functionality that comprise this function into different functions and successfully taken a Test Driven Development approach to the functionality of each of these elements. These elements however aren't exposed for other applications would use.

And so my question is how can/should i easily approach a TDD style solution to verifying that the single method that should be called does function correctly without a lot of duplication in testing or lots of setup required for each test?

I have considered / looked at moving the blocks of functionality into a different class and use Mocking to simulate the responses of the functions used but it doesn't feel right and the individual methods need to write to variables within the main class (it felt really heath robinson).

The code roughly looks like this (i have removed a lot of parameters to make things clearer along with a fair bit of irrelevant code).

public void MethodToTest(string parameter)
{
    IResponse x = null;

    if (function1(parameter))
    {

        if (!function2(parameter,out x))
        {
            function3(parameter, out x);
        }
    }

    // ...
    // more bits of code here
    // ...

    if (x != null)
    {
        x.Success();
    }
}
A: 

IMHO, you have a couple options here:

  1. Break the inner functions out into a different class so you can mock them and verify that they are called. (which you already mentioned)
  2. It sounds like the other methods you created are private methods, and that this is the only public interface into those methods. If so, you should be running those test cases through this function, and verifying the results (you said that those private methods modify variables of the class) instead of testing private methods. If that is too painful, then I would consider reworking your design.

It looks to me like this class is trying to do more than one thing. For example, the first function doesn't return a response but the other two do. In your description you said the function is complex and takes a lot of parameters. Those are both signs that you need to refactor your design.

Shane Fulmer
A: 

Your best option would indeed be mocking function1,2,3 etc. If you cannot move your functions to a separate class you could look into using nested classes to move the functions to, they are able to access the data in the outer class. After that you should be able to use mocks instead of the nested classes for testing purposes.

Update: From looking at your example code I think you could get some inspiration by looking into the visitor pattern and ways of testing that, it might be appropriate.

Simon Groenewolt
A: 

In this case I think you would just mock the method calls as you mentioned.

Typically you would write your test first, and then write the method in a way so that all of the tests pass. I've noticed that when you do it this way, the code that's written is very clean and to the point. Also, each class is very good about only having a single responsibility that can easily be tested.

I don't know what's wrong, but something doesn't smell right, and I think there maybe a more elegant way to do what you're doing.

RexM
+1  A: 

I think you would make your life easier by avoiding the out keyword, and re-writing the code so that the functions either check some condition on the response, OR modify the response, but not both. Something like:

public void MethodToTest(string parameter)
{
    IResponse x = null;

    if (function1(parameter))
    {

        if (!function2Check(parameter, x))
        {
            x = function2Transform(parameter, x);
            x = function3(parameter, x);
        }
    }

    // ...
    // more bits of code here
    // ...

    if (x != null)
    {
        x.Success();
    }
}

That way you can start pulling apart and recombining the pieces of your large method more easily, and in the end you should have something like:

public void MethodToTest(string parameter)
{
    IResponse x = ResponseBuilder.BuildResponse(parameter);

    if (x != null)
    {
        x.Success();
    }
}

... where BuildResponse is where all your current tests will be, and the test for MethodToTest should now be fairly easy to mock the ResponseBuilder.

Mathias