1

I know that every method that doesn't do anything shouldn't be tested (or not even exist). The thing is, that my method does something normally, but for the test-scenario I have to mock that thing that it does. But I would still like to assert the parameters that it would send to the external thing.

Sounds more complicated than it is - Check my snippet for better understanding:

class A {
    @Inject
    private Mailer mailer; // Custom mailer class

    public void doSomething() {
        Date date = new Date(); // dynamic parameter I do not care about in the test
        String parameter = "test"; // The parameter I want to test later

        mailer.sendMail(parameter, date);
    }
}

class ATest {
    @Mock
    @Produces
    private Mailer mailer;

    @Inject
    private A classToTest;

    @Test
    public void testDoSomething() throws Exception {

        classToTest.doSomething();

        assertThat(??).isEqualTo("test"); //How can I get the value of parameter?
    }
}

As you can see I need to mock my emailer, so that I dont send a email everytime a test runs.

It would make no sense to promote parameter to a global variable.

Is there any way to test the value of parameter without changing the code of A? And if not what would be the best solution without messing up my class just for testing?

MauriceNino
  • 6,214
  • 1
  • 23
  • 60
  • 1
    mock your mailer and test that mailer.sendMail(x) has been called – Stultuske May 28 '19 at 10:50
  • @Stultuske My mailer is mocked and I need the value of `parameter` to test. Not just if it got called – MauriceNino May 28 '19 at 10:51
  • so check whether it is called with that parameter. – Stultuske May 28 '19 at 10:55
  • Thats what Im trying to figure out. Haven't found anything like that on SO. @Stultuske – MauriceNino May 28 '19 at 10:58
  • https://stackoverflow.com/questions/9841623/mockito-how-to-verify-method-was-called-on-an-object-created-within-a-method – Stultuske May 28 '19 at 11:03
  • Thats not the same scenario @Stultuske. – MauriceNino May 28 '19 at 11:05
  • yes, it is. it's just a level deeper.Now, you can say it's not the same scenario, but then why would you accept an answer that tells you exactly the same? – Stultuske May 28 '19 at 11:12
  • My question was "How can I access the result of a void that gets sent to a mocked thing". He answered that. That other StackOverflow post doesnt do that. It just tells me how to verify that it got called (which I would have had other ways for too) @Stultuske – MauriceNino May 28 '19 at 11:15
  • A void has no return value thats right, but it can result in something (in this example it results in a sent email). The link you posted did not solve that problem I had. Thank you for your help and concerns though. – MauriceNino May 28 '19 at 11:37
  • you can't test that, you can only test that the method was called and no exception was thrown. The answer you accepted doesn't test more than that: just that the method is called, and what you passed as parameter. – Stultuske May 28 '19 at 11:39
  • `parameter == the result` just to clarify it for you... – MauriceNino May 28 '19 at 11:42

2 Answers2

2

You need to use Mockito.verify:

verify(mailer, times(1)).sendMail("test");

Verify checks what happened with your mocks: how many times a method was called, and what arguments were given to that method.


Update: If you want to exclude certain parameters, you can use org.mockito.Matchers.any - easier to have it as a static import. (NB: if you do ignore some parameters, then the ones you want to INCLUDE now have to be wrapped in org.mockito.Matchers.eq).

verify(mailer, times(1)).sendMail(eq("test"), any(Date.class));
David Lavender
  • 8,021
  • 3
  • 35
  • 55
  • Thanks for the help, but I actually have multiple parameters for sendMail and one of them is the current `Date`. How can I verify that `parameter == "test"`, but ignore the date? I updated my question with a example. – MauriceNino May 28 '19 at 11:03
  • This answers my question. Thank you! I will mark it as accepted, but one small question though: can you do something like `eqContains("te")`? – MauriceNino May 28 '19 at 11:09
  • 1
    nevermind I found it pretty quick now that I know about this. its just `Matchers.contains()`. – MauriceNino May 28 '19 at 11:22
  • 2
    You can also look at `ArgumentCaptor`. Lets say your parameter was a complex Object, with lots of fields - rather than a simple String. You can use an `ArgumentCaptor` to capture the object that was given to your mock, and inspect it afterwards. That's much more powerful, but overkill for simple checks like this – David Lavender May 28 '19 at 11:25
  • Thanks for the hint! – MauriceNino May 28 '19 at 11:34
0

One way is to parameterize the method doSomething with a mutable object, that you can set upon method execution and assert in the test method. Otherwise, you may also check for exception thrown for any negative scenario, something like

@Test(expected = EmailSendException.class)
public void testDoSomething(){
    ....
}
GirishB
  • 134
  • 7
  • this is a horrible plan. what if something else causes such an Exception to be thrown? do understand they are trying to test a happy flow, not an exception – Stultuske May 28 '19 at 11:04
  • Emailer is mocked, so it wont throw anything. I could manually throw something, but that still wouldnt let me check the result of `parameter`. – MauriceNino May 28 '19 at 11:13