4

One of the functions I'm testing is sshing into a machine. I want to mock the ping method, that actually tries to ssh into a machine, since I am not really sshing into a machine.

class I am testing:

public class TestMachine {
    public int ping(host){
    }

    public boolean machineIsGood(host) {
        blah blah
        int val = ping(host);
        blah blah blah
        if(val != 0) return false;
        return true;
    }
}

The test class goes something like this:

public class TestClass {
    public void setUp() {
        TestMachine tester = spy(new TestMachine());
    }

    public void testOne() {
         when(test.ping(anyString()).thenReturn(-1);
         assertFalse(tester.machineIsGood("testHost"));
    }
{

The problem is that when I am running them locally, they work just fine, but on our autobuild system it seems like it is actually calling the real ping and getting an Authentication Exception. I'm going to use mock() instead of spy() since I've read it's a bit weird, but I just can't understand what makes a difference in that it is actually calling the method! Just wondering if anyone else has any insight.

Th3sandm4n
  • 809
  • 4
  • 13
  • 23
  • Okay, so I added the mock instead of spy, but haven't run it through the autobuild because I'm getting NPEs in the ping method now (it relies on some private variables which I can't set since it's mocked), that is originally why I spied. Is there any way to go about this without a lot of code refactoring, or is that my only path? – Th3sandm4n Jan 27 '11 at 17:50

3 Answers3

3

When you use Mockito.spy(), use the Mockito.doReturn() for non-void methods or Mockito.doNothing() for void methods.

In your case:

public class TestClass {
    public void setUp() {
        TestMachine tester = Mockito.spy(new TestMachine());
    }

    public void testOne() {
        doReturn(-1).when(test).ping(Mockito.anyString())
        assertFalse(tester.machineIsGood("testHost"));
    }
}
Tarek
  • 3,080
  • 5
  • 38
  • 54
3

In my experience, you should not use mocks to test interactions between methods in the same class.

What this tells us is that you should decouple your SUT (system under test) from the external dependency that you need to replace with a test double (the ping that you do not want to call "for real" in your unit tests).


public class Pinger {
    public int ping(String host) {
        // yadda yadda
    }
}

public class TestMachine {

    private final Pinger pinger;

    public TestMachine(final Pinger pinger) {
        this.pinger = pinger;
    }

    public boolean machineIsGood(host) {
        // blah blah
        int val = pinger.ping(host);
        // blah blah blah
        return val == 0;
    }
}

public class TestMachineTest {
    @Test
    public void testOne() {
        final Pinger pinger = mock(Pinger.class);
        when(pinger.ping(anyString())).thenReturn(-1);

        TestMachine tester = new TestMachine(pinger);
        assertFalse(tester.machineIsGood("testHost"));
    }
}

HTH

Thomas Dufour
  • 1,872
  • 1
  • 16
  • 20
2
public class TestClass {
  private TestMachine tester;
  public void setUp() {         
    tester = mock(TestMachine.class);     
  }      

  public void testOne() {
          when(tester.ping(anyString()).thenReturn(-1);
          assertFalse(tester.machineIsGood("testHost"));
     }
} 
esmiralha
  • 10,587
  • 1
  • 16
  • 20
  • The only problem is that in ping it uses some private variables (that are not instantiated because the class is mocked). Looks like I'm just going to have to restructure the code to make it more test friendly. – Th3sandm4n Jan 27 '11 at 20:33