-1

I'm wriring test to check if method returns correct string. But even if method returns null the test is passed! Why it happens? How correctly to write the test? Thank you!

// TestMyObj.java: My test class
public class TestMyObj {
    @InjectMocks
    private MyClass myClass;

    @Mock
    TestObj testObj;

    private final String test = "test";

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);  // or use mockito runner
    }

    @Test
    public void test() {
        when(testObj.get()).thenReturn(test);
        Assert.assertTrue(myClass.get().equals(test));
        verify(testObj).get();
    }
}

// MyClass.java: Class which uses my object
public class MyClass {
    private TestObj testObj;

    public MyClass() {}
    public MyClass(TestObj testObj) { this.testObj = testObj; }
    String get() { return testObj.get(); }
}

// TestObj.java: My testing object 
public class TestObj {
    String get() { return null; }
}
Kiryl Ivanou
  • 1,015
  • 2
  • 12
  • 22
  • Hey, why -1, what's wrong with the question? I didn't find the answer between similar questions about mock tests which pass. – Kiryl Ivanou Nov 24 '17 at 19:36
  • 3
    What do you think `when(testObj.get()).thenReturn(test);` does? – JB Nizet Nov 24 '17 at 19:36
  • If you're testing `TestObj` why bring `MyClass` in the mix? If you're testing `MyClass`, why is the test class named `TestMyObj`? Then you set up a mock to return a string "test", and complain that you're not getting a null. There nothing right about this test, and apparently, you don't understand mocking at all. – Abhijit Sarkar Nov 24 '17 at 19:37
  • JB Nizet, it's like i expect that my method will return "test" (test="test"). – Kiryl Ivanou Nov 24 '17 at 19:40
  • No, that's not what this line does. It **tells** the **mock** TestObj (i.e. not a real TestObj), to always return `test` when its `get()` method is called. You really, really need to read about the principle of mocking, and the documentation of Mockito. Also read https://stackoverflow.com/a/28783849/571407 – JB Nizet Nov 24 '17 at 19:44

2 Answers2

2

myClass.get() returns testObj.get(); at the same time, with when(...) you instruct your testObj.get() to return test.

So myClass.get() is basically equivalent to test, and Assert.assertTrue(myClass.get().equals(test)) reduces to Assert.assertTrue(test.equals(test)) which asserts ok when test is not null (and it is not null in your case).

By the way, instead of

Assert.assertTrue(expected.equals(actual));

it is much better to write

Assert.assertEquals(expected, actual);

It will give you a diagnostic message on failure from which you will see what value was expected and what value was actually given to the second argument.

So I would rewrite the same test like

@Test
public void test() {
    when(testObj.get()).thenReturn("test");
    assertEquals("test", myClass.get());
    verify(testObj).get();
}

This seems to make sense: we are testing that MyClass calls its collaborator testObj correctly and returns its return value to us.

Using constants instead of test variable seems the right thing here. First, as the constant is used in two adjacent lines, no problems occur with 'I changed my constant in one place and forgot to do it in another'. And second, there is no indirection level now (which was introduced with that test variable), so the code is a bit easier to understand.

Roman Puchkovskiy
  • 11,415
  • 5
  • 36
  • 72
2

As the others have explained - start by carefully reading about the concepts you are using.

The key thing here: you are mocking that instance of your test class. Therefore the real implementation of that method that returns null does not matter at all. Because you create a mocked object and instruct Mockito to return a non null value upon calls to get(). Therefore the real method body returning null is never executed in the code you are showing us.

That is all there is to this.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • 1
    @KirylIvanou Have you read https://stackoverflow.com/a/28783849/571407? What don't you understand? – JB Nizet Nov 24 '17 at 20:26
  • 1
    @JBNizet, thank you! Now I understand everything:) I'd say briefly and clear about mock: mocking object is *not* for testing this object but to *use* it for testing *another* object of class where this real object is used. – Kiryl Ivanou Nov 24 '17 at 21:10