Meow
Meow

Reputation: 19071

How to write unit test using mock object?

The more I read mock example, the more I get confused...

I have classA method eat() that calls FatDude class eatThemAll()

public class classA {

   FatDude dude = new FatDude();

   public String eat() {
        String result = dude.eatThemAll();
   }
}

public class FatDude {
   public String eatThemAll() {
       return "never full";
   }
}

Now I want to test classA eat() method by mocking FatDude class.

public class MockFatDude extends FatDude {
   //override
   public String eatThemAll() {
      return "very full";
   }
}
-------------  test --------------
public class DoTest {

    public void runTest() {
         classA cl = new ClassA();
         String out = cl.eat();
         assertEqual(out, "very full");
    }
}

This DoTest runTest() won't use MockFatDude class of course. One way I can think is to change the code to pass FatDude to eat() method of ClassA like:

public class classA {

       public String eat(FatDude dude) {
            String result = dude.eatThemAll();
       }
   }

Then change my test method to:

public class DoTest {

        public void runTest() {
             classA cl = new ClassA();
             String out = cl.eat(new MockFatDude());
             assertEqual(out, "very full");
        }
    }

But as you can see, I had to change the source code to meet my need. Is this the right way to do? What if I am not allowed to change my source code? I know if I apply TDD concept, it is OK to change source code but I would like to hear some opinion or advice if what I have shown above is right way to do.

Upvotes: 4

Views: 5087

Answers (2)

StuartLC
StuartLC

Reputation: 107247

Mocking and the Dependency Inversion Principle (DIP) go hand in hand, and in most languages, Mocks work best by decoupling classes by means of interfaces.

In your instance, this will work without you needing to change code: (Edit : I mean, in future, if you design your app this way, you won't need to change code to mock dependencies :))

  • Abstract an interface IDude
  • Concrete classes FatDude (and MockFatDude) should implement IDude interface
  • provide a mechanism for an IDude instance to be 'set' or injected into classA - Dependency Injection (constructor or get / sets); or Service Locator pattern work best (to replace a concrete classfactory)

Also note that many mocking frameworks actually allow you to build up the Mock concrete class 'on the fly' (see MoQ et al), so you can create the functionality of MockFatDude directly in your unit test.

Upvotes: 4

Robert S Ciaccio
Robert S Ciaccio

Reputation: 2715

Yes. You've stumbled on some good design directly because of your unit test. If you look more closely, you'll see that you removed the coupling between classA and FatDude. Now FatDude can be an interface for behavior that gets passed in when needed. ClassA doesn't need to know what kind of FatDude it's getting, or how to construct a FatDude (with cheeseburgers?).

Your solution is exactly what I would have done. There's nothing wrong with changing your code to accomodate TDD, as long as you understand the reasons and the benfits/drawbacks to making such changes.

Upvotes: 2

Related Questions