4

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.

Meow
  • 18,371
  • 52
  • 136
  • 180
  • Is it java or C#? what tools do you use? Please, add appropriate tags. Thank you. – Maxim Sloyko Dec 09 '10 at 08:17
  • 1
    @maksymko: i don't think the language or the tools are important to this question other than the fact that its an object-oriented language. – Robert S Ciaccio Dec 09 '10 at 08:22
  • @calavera: i meant it just as a clarification for more proper categorization/filtering etc, not as a way to help answer the question. – Maxim Sloyko Dec 09 '10 at 12:31
  • @maksymko: i'm not using any tools like jmock or easymock since i wanted to understand what is mock and how to use. Most of tutorial shows example using mock tools which makes hard to understand. – Meow Dec 09 '10 at 23:22

2 Answers2

4

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.

StuartLC
  • 104,537
  • 17
  • 209
  • 285
  • @noonb: I think he was implying abstraction in his example solution, otherwise he would have needed an override. – Robert S Ciaccio Dec 09 '10 at 08:21
  • As the code above looks like Java rather than C#, I'm going to add a link to http://stackoverflow.com/questions/22697/whats-the-best-mock-framework-for-java – Michael Lloyd Lee mlk Dec 09 '10 at 09:43
  • In non-DI environments, you can also easily build mock objects in pure java by using something similar to getter injection on the class being tested and insert anonymous inner classes that act as mocks. – revdrjrr Dec 10 '10 at 00:15
2

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.

Robert S Ciaccio
  • 2,675
  • 1
  • 19
  • 21