Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to query against arguments passed to a Mockito mocked object?

Tags:

java

mockito

I'm learning Mockito at the moment and one of the things I'm doing to consolidate my learning is converting an old JUnit test from using a hand rolled mock class to one which uses Mockito mocks instead. However, I've run into a situation I'm not sure how to handle.

Specifically, my unit under test constructs a String which gets passed to the mocked object as a parameter in a method call on it. I'd like to test that the String is constructed correctly. The challenge is that part of the String is a hash key which is generated internally and changes on every invocation. One solution that would work would be to get the hash generation under my control and inject a dummy generator for test execution. However, this is a fair bit of work.

My old hand rolled mock class would store the arguments passed to it which I could query in my test. This allowed me to query the start and end of the String via the following:

assertTrue(mockFtpClient.getFilePathAndName().startsWith("/data/inbound/XJSLGG."));
assertTrue(mockFtpClient.getFilePathAndName().endsWith(".pdf"));

This was a sufficent enough test for my taste. So my question is, is it possible using Mockito to query or get a hold of the arguments passed to a method so that i can perform something similiar to the above?

UPDATE 24/06/2011: At this point I have excepted Gnon's answer. However, I have since discovered something which works better for me. Namely ArgumentCaptor. Here's how it works:

ArgumentCaptor<String> fileNameArgument = ArgumentCaptor.forClass(String.class);
verify(mockFtpClient).putFileOnServer(fileNameArgument.capture());
assertTrue(fileNameArgument.getValue().startsWith(START_FILE_NAME) &&
           fileNameArgument.getValue().endsWith(END_FILE_NAME));

The javadoc for Mockito state that ArgumentCaptor is generally a better choice when you have a one-off specific argument matching requirement, as I do here.

like image 361
Chris Knight Avatar asked Jun 23 '11 16:06

Chris Knight


2 Answers

Basically you need to use argThat() in Mockito, that lets you treat a Hamcrest Matcher as a verification argument. Here is the code you use to make custom assertions about a passed-in argument:

@Test
public void testname() throws Exception {
    HashReceiver receiver = mock(HashReceiver.class);
    receiver.set("hash");
    verify(receiver).set(argThat(new HashMatcher()));
}

class HashMatcher extends BaseMatcher<String> {
    @Override
    public boolean matches(Object item) {
        String hash = (String) item;
        if (hash.startsWith("/data/inbound/XJSLGG.") && hash.endsWith(".pdf"))
            return true;
        return false;
    }
}

// Mocked
class HashReceiver {
    public void set(String hash) {
    }
}

You may be able to use a generic matcher instead, or a combination of generic matchers.

like image 83
Garrett Hall Avatar answered Oct 21 '22 14:10

Garrett Hall


Have a look at the accepted answer to this question mockito-how-to-make-a-method-return-an-argument-that-was-passed-to-it it will show you how to get a hold of the arguments passed to your mock method invocation.

like image 23
digitaljoel Avatar answered Oct 21 '22 13:10

digitaljoel