Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JUnit Test method that use other methods in the same object

Hello I am struggling with simple problem.

General idea:

class Foo(){
  public boolean method1();
  public String method2();
  public String method3();
  public String shortcut(){
    return (method1() == true) ? method2() : method3();
  }
}

How should I test shortcut method?

I know how to mock objects and test methods that use other object. Sample:

class Car{
  public boolean start(){};
  public boolean stop(){};
  public boolean drive(int km){};
}
class CarAutoPilot(){
  public boolean hasGotExternalDevicesAttached(){
     //Hardware specific func and api calls
     //check if gps is available 
     //check if speaker is on
     //check if display is on 
  }
  public boolean drive(Car car, int km){
    //drive
    boolean found = hasGotExternalDevicesAttached();
    boolean start = c.start();
    boolean drive = c.drive(km);
    boolean stop = c.stop();
    return (found && start && drive && stop) == true;   
  }
}

class CarAutoPilotTest(){
   @Test
   public void shouldDriveTenKm(){
     Car carMock = EasyMock.Create(Car.class);
     EasyMock.expect(carMock.start()).andReturns(true);
     EasyMock.expect(carMock.drive()).andReturns(true);
     EasyMock.expect(carMock.stop()).andReturns(true);
     EasyMock.reply(carMock);     

     CarAutoPilot cap = new CarAutoPilot();
     boolean result = cap.drive(cap,10);
     Assert.assertTrue(result);
     EasyMock.verify(carMock);
   }
}

But what about hasGotExternalDevicesAttached() method? This is only sample not real scenario. How should I test drive method? Should I also mock hasGotExternalDevicesAttached function?

Can I mock class that is being tested?

like image 239
kuki1384 Avatar asked Feb 23 '12 07:02

kuki1384


3 Answers

I would create one test for each method. If you lower the complexity then it is much easier to test.

these should have one test each:

  public boolean method1();
  public String method2();
  public String method3();

There is no need to test the last method since it calls your other methods, how ever, if that method changes (since im guessing its only a sample code) and it has more logic in it then you should have one test method for that as well.

When it comes to the hasGotExternalDevicesAttached() you should create a mocker for all external io calls that you cant test.

If you want to improve your skill within testing I would recommend that you read The Art of Unit Testing. This is in my opinion the best book for beginners to learn and study the art of unit testing.

like image 100
Marthin Avatar answered Nov 10 '22 23:11

Marthin


You can create a subclass of CarAutoPilot in which you override hasGotExternalDevicesAttached(), and run the test with an instance of this subclass.

You can do it inline:

CarAutoPilot cap = new CarAutoPilot() {
    public boolean hasGotExternalDevicesAttached(){
        // return true or false depending on what you want to test
    }
};

This way you can create a valid unit test for the rest of CarAutoPilot's behaviour.

You can call this a poor man's partial mock if you wish :-)

like image 41
The Nail Avatar answered Nov 10 '22 22:11

The Nail


Yes you can, using the EasyMock Class Extension library. Look for "Partial mocking" in the documentation of EasyMock.

The idea is to mock only one (or some) of the methods of an object, and test the methods that depend on the mocked method.

like image 28
JB Nizet Avatar answered Nov 10 '22 21:11

JB Nizet