23

When unit testing functions of a class that has private functions that require online functionality. How would one go about testing it?

For example:

public class Foo
{
    public int methodA()
    {
         int val = goOnlineToGetVal();

         return val;
    }

    private int goOnlineToGetVal()
    {
        CloudService c = new CloudService();
        int oval = c.getValueFromService();
        return oval;
    }
}

If I were to test function: 'methodA()' it would attempt to use 'goOnlineToGetVal()' which would in turn try to go online however, if this test was done without functionality. How would I go about 100% Class coverage without going online?

3

2 Answers 2

77

new CloudService()

And there's your problem.

Modern OO design recommends that this sort of dependency be passed in rather than constructed directly. This can be passed into the function itself, or to the class at construction time. It could also be grabbed or aggregated by an Inversion of Control container if that sort of complexity is warranted.

At that point, it becomes fairly trivial to pass in a mock/fake service to provide you with your "online" data during testing. Better yet, it allows your software to be sufficiently flexible, so that you can quickly adapt should some (governmental?) client comes along and doesn't want to use the cloud for their values. Or you want to dump one cloud provider for another. Or...

8
  • 7
    I think I just got a lot closer to understanding what the heck Dependency Injection is.
    – marczellm
    Commented Sep 16, 2014 at 20:09
  • Where is the best place to create all the instances that my application needs? As close to the top of my application as possible? You can only apply dependency injection so far; at some point you'll need to create the instances yourself instead of having them passed as arguments.
    – Paul
    Commented Sep 16, 2014 at 20:10
  • 3
    @Paul - It depends. In my experience, applications very often look like binary trees - one class/function/module glues two together to provide some more complex behavior. One of those "glue" classes is the one that specifies the concrete implementation, which in turn is used by something above that glues it with something else, which in turn... until you eventually get to your entrypoint that glues the big pieces together coherently. The "best" place is the place that lets your code do what it needs to do, without making it do or know about things it shouldn't. It will vary.
    – Telastyn
    Commented Sep 16, 2014 at 20:24
  • 2
    @Paul Usually your application is divided between a "library", which is directly tested and should use this kind of dependency injection, and application-specific code. The latter usually boils down to some GUI, some web service or some command line interface that directly calls the library with user-supplied data. Essentially, application-specific code will create the concrete implementations that the dependency-injected library expects.
    – Darkhogg
    Commented Sep 17, 2014 at 7:50
  • @Paul Take a look at IoC containers like Castle Windsor, StructureMap, Ninject and Unity. They are by no means the only way to do dependency injection, but they can be very informative in terms of thinking about constructing an object graph, from the top down Commented Sep 17, 2014 at 13:57
37

I would implement it like this:

public class Foo
{
    private ICloudService cloudService;

    public Foo(ICloudService s)
    {
       cloudService=s;
    }

    public int methodA()
    {
         int val = goOnlineToGetVal();

         return val;
    }

    private int goOnlineToGetVal()
    {
        int oval = cloudService.getValueFromService();
        return oval;
    }
}

The interface ICloudService can be either implemented with a mock for testing, or with the "real" cloudservice. When the instantiation new CloudService() is mandatory for every call of getValueFromService, or CloudServiceis from a 3rd party API which cannot be changed, implement a wrapper, deriving from ICloudService and making the appropriate calls.

1
  • 1
    This is definitely the way to go. There are class libraries that can mock an interface giving you absolute control of the test. Commented Sep 16, 2014 at 0:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.