IAmYourFaja
IAmYourFaja

Reputation: 56894

How to unit test a high-dependency method?

Fairly new to the concept of unit testing here. I'm using Java (JUnit) but this is really a question that applies to any type of unit testing.

Say I have number of objects:

And they are all in the same package. Let's just say that Widget has a run() method that looks like this:

public void run() {
    Foo foo = new Foo(true, 1);
    Fizz fizz = FizzFactory.getInstance(Widget.class);
    Buzz buzz = getBuzz();

    int someData = fizz.process(buzz);
    foo.execute(someData);
}

So here we have several objects (and their methods) being called inside of run(). How does one actually go about unit testing ("mocking" or "stubbing" out Foo, Fizz and Buzz) this method without crossing the grey line into integration testing?

Upvotes: 0

Views: 141

Answers (2)

Paul Rubel
Paul Rubel

Reputation: 27222

If you're making static calls to create objects in your method you're likely "doing it wrong". Note that a constructor is just a special kind of static method.

Misko Hevery has number of very good posts on this topic.

If you want to be able to test your classes you need to be able to exchange your "business logic" with testing mocks or stubs. You do that by ensuring that constructors don't do real work, but rather just set up objects that have been constructed in other places.

If I were to refactor this to be testable I'd have something like so:

public class X {
  public X(FooFactory ff , FizzFactory fz, BuzzFactory bf) {
      _fooFactory = ff;
      _fizzFactory = fz;
      _buzzFactory = bf;
  }

  public void run() {
    Foo foo = _fooFactory.newFoo(true,1); 
    Fizz fizz = _fizzFactory.getInstance(Widget.class);
    Buzz buzz = _buzzFactory.getBuzz();

    int someData = fizz.process(buzz);
    foo.execute(someData);
  }
}

Using the factories above (or subclasses that mock out the behavior) you've insulated the testing of X to just the methods it calls. You could set up expectations for the run method and test them, but not have to deal with fizz.process, say, connecting to a DB.

Note that not much is happening here, no branching, so the test would be fairly straightforward. The trick of not calling new in the constructor or static methods to create objects should carry over though.

A good keyword while looking for info about this is Dependency Injection.

Upvotes: 2

Maess
Maess

Reputation: 4146

My personal opinion is that, in this case, you have seperate tests for

Foo(bool, int)
 FizzFactory.getInstance
getBuzz()
fizz.process()

and

foo.execute

run() is an integration of all the above methods.

Upvotes: 0

Related Questions