Reputation: 427
I wrote an event handler for Stash to send out messages via a messaging bus architecture. Here's an example of one from my fedmsgEventListener
class:
@EventListener
public void opened(PullRequestOpenedEvent event)
{
HashMap<String, Object> message = prExtracter(event);
String originProjectKey = ((HashMap<String, Object>)message.get("source")).get("project_key").toString();
String originRepo = ((HashMap<String, Object>)message.get("source")).get("repository").toString();
String topic = originProjectKey + "." + originRepo + ".pullrequest.opened";
sendMessage(topic, message);
}
It gets an event, extracts information out of it, constructs a topic based on the information in the event, and invokes a method to send the message. I need to write unit tests for all of these event handlers.
Here is the class that runs the first test I am attempting to implement:
import org.junit.Test;
import com.cray.stash.MyPluginComponent;
import com.cray.stash.MyPluginComponentImpl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class MyComponentUnitTest
{
@Test
public void testMyName()
{
MyPluginComponent component = new MyPluginComponentImpl(null);
assertTrue(component.openPullRequest().contains(".pullrequest.opened"));
}
}
and then here is the class and method that the test calls:
import com.atlassian.sal.api.ApplicationProperties;
import com.atlassian.stash.event.pull.*;
import org.mockito.Mock;
import static org.mockito.Mockito.*;
public class MyPluginComponentImpl implements MyPluginComponent
{
@Mock private PullRequestEvent event;
@Mock private PullRequestOpenedEvent opened;
@Mock private FedmsgEventListener fedmsgEventListener;
public MyPluginComponentImpl(ApplicationProperties applicationProperties)
{
this.applicationProperties = applicationProperties;
}
public String openPullRequest()
{
fedmsgEventListener.opened(opened);
return fedmsgEventListener.getTopic();
}
}
As of now, the method throws a NullPointerException
because the fedmsgEventListener
and the PullRequestEvent
are both mocked objects and therefore null.
Is this the best way to go about unit testing this scenario? From a high level, this is all I want to do: trigger the event, see that the topic got changed to a string including a certain string.
Upvotes: 4
Views: 13290
Reputation: 32323
You are using Mockito completely wrong. Sorry. First of all, @Mock
doesn't work without using initMocks
or MockitoJUnitRunner
, but I wouldn't do it that way anyway. A mock is not null; you should be able to call methods on mocks; in your case you didn't initialize / create the mocks and that's why they were null.
First, identify the class you're trying to test. It looks like it's FedmsgEventListener
here. Then, interact with a real instance of that class using mock objects and data structures instead of real objects that have dependencies and so forth. Note, I am using Hamcrest 1.3 here.
A mocking based test is built up in three phases:
Mockito.verify
and JUnit/Hamcrest assert
methods to ensure that things worked the way you expected.You might do something like this:
import static org.mockito.Mockito.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
private HashMap<String, Object> createMessageDetails(String project_key, String repository) {
HashMap<String, Object> details = new HashMap<>();
details.put("project_key", project_key);
details.put("repository", repository);
return details;
}
public class FedmsgEventListenerTest {
@Test
public void testOpened() {
// when
PullRequestOpenedEvent event = mock(PullRequestOpenedEvent.class);
when(event.someMethodForPrExtracterYouHaventShownMe()).thenReturn(createMessageDetails("myKey", "myRepo"));
// then
FedmsgEventListener listener = new FedmsgEventListener();
listener.opened(event);
// verify
assertThat(event.getTopic(), containsString(".pullrequest.opened"));
verify(event).someMethodForPrExtracterYouHaventShownMe();
}
}
This code is probably not exactly what you need, but you haven't shown me enough of the code you're trying to test for me to get it exactly right. However, I think this should be enough to get you started.
As an aside, if you aren't able to create a real instance of your class with mocked dependencies, then that is a code smell and your code should be refactored. This is one reason why statics are such a bad idea, because if your code is accessing global state via statics then you have to set up the global state with your statics. Make your class able to work with mock dependencies, pass them as arguments to the constructor, specify the mock behavior with when
, and then assert / verify the results.
Upvotes: 6