How do I mock an Event Handler? - java

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.

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:
Create - Create your mocks, and then state that "when" an interaction with that mock occurs, do something.
Interact - Interact with your objects in the way you're trying to test.
Verify - Use 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.

Related

Using factory method for creating common Mockito stubbings in Java

In project I am working on we have a bunch of commonly used helpers. Consider the following example:
public class ServiceHelper {
public HttpServletRequest() getRequest() { ... }
public Model getModel() { ... }
public UserCache getUserCache() { ... }
public ComponentContainer getComponentContainer() { ... }
}
Imagine this helper is being used across the whole application by every web service we have. Then, in order to test these services I need to mock it. Each time. But what if I create a factory of some kind instead, something like:
public class ServiceHelperMockStore {
public static ServiceHelper create() {
return init();
}
public static ServiceHelper create(final Model model) {
final ServiceHelper helper = init();
when(helper.getModel()).thenReturn(model);
return helper;
}
private static ServiceHelper init() {
final ServiceHelper helper = mock(ServiceHelper.class);
final HttpServletRequest request = mock(HttpServletRequest.class);
final Model model = mock(Model.class);
final UserCache userCache = mock(UserCache.class);
final ComponentContainer container = mock(ComponentContainer.class);
final BusinessRules businessRules= mock(BusinessRules.class);
final ModelTransformer modelTransformer = mock(ModelTransformer.class);
when(helper.getRequest()).thenReturn(request);
when(helper.getModel()).thenReturn(model);
when(helper.getUserCache()).thenReturn(userCache);
when(helper.getComponentContainer()).thenReturn(container);
when(container.getComponent(BusinessRules.class)).thenReturn(businessRules);
when(componentContainer.getComponent(ModelTransformer.class)).thenReturn(modelTransformer);
return helper;
}
}
This factory nicely fit my purposes and oftentimes I can completely avoid using 'mock' and 'when' in the actual test suites. Instead, I can do the following:
#RunWith(MockitoJUnitRunner.Silent.class)
public class ModelServiceTest {
private final Model model = new Model();
private final ServiceHelper serviceHelper = ServiceHelperMockStore.create(model);
private final BusinessRules businessRules = serviceHelper.getComponentContainer().getComponent(BusinessRules.class);
private final ModelType modelType1 = new ModelType();
private final ModelType modelType2 = new ModelType();
private final ModelService modelService = new ModelService(serviceHelper);
#Before
public void setUp() {
modelType1.setItemId("item1");
modelType2.setItemId("item2");
model.setTypes(modelType1, modelType2);
when(businessRules.get("type")).thenReturn(modelType1);
}
...tests...
}
So instead of creating a lot of mocks in the ModelServiceTest, I can just access the predefined ones, like:
BusinessRules businessRules = serviceHelper.getComponentContainer().getComponent(BusinessRules.class);
and this even reflect my helper's API. Also, I can provide my own mock or stub passing parameters to my factory method or using some different approach.
The only problem I have is UnnecessaryStubbingException being thrown by Mockito as normally I don't use all those stubbings I've created per each test file. So I have to use MockitoJUnitRunner.Silent runner to silent the error and according to the mockito api docs it is not recommended.
So I am seeking for an advice what kind of approach must be chosen in this case. Am I doing it right or there is some other way? Or, maybe, using such kind of factories is a bad style of programming in relation to unit tests as it hides some initialization and makes happening things less evident so I must do just a plain copy of my code between test suits?
The fact that you need this identical complex mock configuration at different places shows that your code violates the Law of Demeter (Don't talk to strangers).
A unit should only get dependencies it actually interacts with (other than only to getting another dependency from it).
So instead of creating a lot of mocks in the ModelServiceTest, I can just access the predefined ones,
You Unittests are not only verification of correct behavior but also minimal examples how to use the CUT (Code under test).
The configuration of the CUTs dependencies is an essential part of that example and should be easily accessible to the reader of the tests.
I'd strongly discourage from "factories for mocks" especially it they were moved to other classes (in the test folder).

Unit testing when part of the class needs to be mocked

I have a class that I am trying to unit test. This class extends another class that I am not interested in unit testing at this time.
The following code is an over simplification of the code I am trying to test.
package com.example.somePackage;
public class ApiBase {
protected <T extends SomeClass> t getApi(Class<T> apiClass) {/* some logic*/}
}
package com.example.anotherPackage;
public MagicApiImpl extends ApiBase {
private final MagicApiHandler apiHandler = new MagicApiHandler();
public String doSomeStuff(String someString) {
final BookApi bookApi = getApi(BookApi.class);
// some logic
return apiHandler.someMethod(bookApi, someString);
}
}
I would like to test doSomeStuff() on MagicApiImpl The part I would like to mock is what comes back in getApi().
At first go I tried simply creating an Instance of MagicApiImpl and setting all the behind the scenes things that happen but that started to become over complex for the scenario I want to test and the number of times I need to test it in other classes. I will handle the testing of the logic in getApi() in a test of its own.
It would be helpful to use EasyMock to test this as it is what a majority of the tests for this project are written in but I would not be overly apposed to using mockito.
Edit
Okay I was reading about the Mockito.spy() That would have been wonderful but sadly getApi is protected and in another package. Worst case I could fall back on placing all the tests in that package but that makes it difficult track code.
Using Easymock partial mocks your test should look like this:
#Test
public void test() {
MagicApiImpl impl = EasyMock.createMockBuilder(MagicApiImpl.class)
.addMockedMethod("getApi")
.createMock();
EasyMock.expect(impl.getApi(BookApi.class)).andReturn(/**Wharever you need*/);
EasyMock.replay(impl);
String input = "INPUT";
String output = impl.doSomeStuff(input);
System.out.println("The OUTPUT is: " + output);
EasyMock.verify(impl);
//Run asserts here
}
Reference: http://easymock.org/user-guide.html#mocking-partial

Mockito - Test if a method of a class is called

I am new to writing tests in java, and seem to be unable to test if a method of a class is called.
I am sending metrics to datadog, and want to test in the code if a function of another class was called.
It says I need to mock first, but I couldn't get it to work.
MetricRecorder.java
import com.timgroup.statsd.StatsDClient;
import com.timgroup.statsd.NonBlockingStatsDClient;
import com.google.common.base.Preconditions;
public class MetricRecorder {
private final String namespace;
private final static StatsDClient metrics = new NonBlockingStatsDClient(
"my.prefix",
"localhost",
8125,
new String[] {"tag:value"}
);
public MetricRecorder(String namespace) {
Preconditions.checkNotNull(namespace);
this.namespace = namespace;
}
public void inc(String metricName) {
this.inc(metricName, 1);
}
public void inc(final String metricName, final long value) {
Preconditions.checkNotNull(metricName);
try {
metrics.recordHistogramValue(MetricRecorder.name(namespace, metricName), value);
} catch (Exception e) {
logger.warn("Unable to record metric {} due to :", metricName, e);
}
}
...
}
MetricRecorderTest.java
public class MetricsRecorderTest {
#Test
public void metricsRecorderTest() {
MetricRecorder recorder = new MetricRecorder("dev");
recorder.inc("foo", 1);
verify(recorder.metrics, times(1)).recordHistogramValue(eq("dev.foo"), 1);
}
}
When I run the test I get this => org.mockito.exceptions.misusing.NotAMockException:
Argument passed to verify() is of type NonBlockingStatsDClient and is not a mock!
Any idea of how I should be testing if recordHistogramValue was called, and if so with what arguments?
Since it looks like StatsDClient is an interface of some kind, it would make your testing effort easier to simply inject this dependency into your object. Even if you're not using an IoC container like Spring or Guice, you can still somewhat control this simply by passing an instance of it in through the constructor.
public MetricRecorder(String namespace, StatsDClient client) {
Preconditions.checkNotNull(namespace);
Preconditions.checkNotNull(client);
this.namespace = namespace;
this.client = client;
}
This will make your testing simpler since all you realistically need to do is mock the object passed in during test.
Right now, the reason it's failing is because you're newing up the instance, and Mockito (in this current configuration) isn't equipped to mock the newed instance. In all honesty, this set up will make testing simpler to conduct, and you should only need your client configured in one area.
#RunWith(MockitoJUnitRunner.class)
public class MetricsRecorderTest {
#Test
public void metricsRecorderTest() {
StatsDClient dClientMock = Mockito.mock(StatsDClient.class);
MetricRecorder recorder = new MetricRecorder("dev", dClientMock);
recorder.inc("foo", 1);
verify(recorder.metrics).recordHistogramValue(eq("dev.foo"), 1);
}
}
You are getting things wrong here. You don't use a mocking framework to test your "class under test".
You use the mocking framework to create mocked objects; which you then pass to your "class under test" within a test case. Then your "code under test" calls methods on the mocked object; and by controlling returned values (or by verifying what happens to your mock); that is how you write your testcases.
So, your testcase for a MetricRecorder doesn't mock a MetricRecorder; it should mock the StatsDClient class; and as Makoto suggests; use dependency injection to put an object of that class into MetricRecorder.
Besides: basically writing "test-able" code is something that needs to be practiced. I wholeheartedly recommend you to watch these videos if you are serious about getting in this business. All of them; really (worth each second!).

What is the difference between a Seam and a Mock?

Its being a few months since I am working with java legacy code, this are some of the things I am dealing with:
0% test coverage.
Huge functions in occasions I even saw some with more than 300 lines of code.
Lots of private methods and in occasions static methods.
Highly tight coupled code.
At the beginning I was very confused, I found difficult to use TDD in the legacy. After doing katas for weeks and practicing my unit testing and mocking skills, my fear has decreased and I feel a bit more confident. Recently I discovered a book called: working effectivelly with legacy, I didn't read it, I just had a look at the table of contents and I discovered something that is new for me, The Seams. Apparently this is very important when working in the legacy.
I think that this Seams could help me alot in breaking dependencies and make my code testeable so I can increase the code coverage and make my unit testing more precise.
But I have a lot of doubts:
Can somebody explain me the difference between a seam and a mock?
Do Seams, break TDD rules in what regards not touching production code, before is tested?
Could you show me some simple example that compares a Seam and a Mock?
Below I would like to paste an example I did today where I tried to break a dependency with the goal of making the code testeable and finally increasing test coverage. I would appreciate if you could comment a bit if you see some mistakes?
This is how the legacy code looked like at the beginning:
public class ABitOfLegacy
{
private String sampleTitle;
String output;
public void doSomeProcessing(HttpServletRequest request) {
String [] values = request.getParameterValues(sampleTitle);
if (values != null && values.length > 0)
{
output = sampleTitle + new Date().toString() + values[0];
}
}
}
If I just add a unit test that calls that method and asserts that variable output, has a certain value after the call,then I would be making a mistake, because I am not unit testing, I would be doing integration testing. So what I need to do, Is get rid of the dependency I have in the parameter. To do So, I replace the parameter with an interface:
public class ABitOfLegacy
{
private String sampleTitle;
String output;
public void doSomeProcessing(ParameterSource request) {
String [] values = request.getParameters(sampleTitle);
if (values != null && values.length > 0)
{
output = sampleTitle + new Date().toString() + values[0];
}
}
}
This is how the interface looks like:
public interface ParameterSource {
String[] getParameters(String name);
}
The next thing I do, is create my own implementation of that interface but I include the HttpServletRequest as a global variable and I implement the method of the interface using the method/s of HttpServletRequest:
public class HttpServletRequestParameterSource implements ParameterSource {
private HttpServletRequest request;
public HttpServletRequestParameterSource(HttpServletRequest request) {
this.request = request;
}
public String[] getParameters(String name) {
return request.getParameterValues(name);
}
}
Until this point, I think that all the modifications on the production code were safe.
Now I create the Seam in my test package. If I understood well, now I am able to safely change the behavoir of the Seam. This is how I do it:
public class FakeParameterSource implements ParameterSource {
public String[] values = {"ParamA","ParamB","ParamC"};
public String[] getParameters(String name) {
return values;
}
}
And the final step, would be to get support from the Seam, to test the original behavoir of the method.
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import code.ABitOfLegacyRefactored;
import static org.hamcrest.Matchers.*;
public class ABitOfLegacySpecification {
private ABitOfLegacy aBitOfLegacy;
private String EMPTY = null;
#Before
public void initialize() {
aBitOfLegacy = new ABitOfLegacy();
}
#Test
public void
the_output_gets_populated_when_the_request_is_not_empty
() {
FakeParameterSource fakeParameterSource = new FakeParameterSource();
aBitOfLegacy.doSomeProcessing(fakeParameterSource);
assertThat(aBitOfLegacy.output,not(EMPTY));
}
#Test(expected=NullPointerException.class)
public void
should_throw_an_exception_if_the_request_is_null
() {
aBitOfLegacy.doSomeProcessing(null);
}
}
This will give me 100% test coverage.
I appreciate your thoughts:
Did I break the dependency correctly?
Are the unit tests missing something?
What could be done better?
Is this example good enough to help me understand the difference between a Seam and a Mock?
How could a mock help me here if I don't use the Seam?
A seam is a place in the code that you can insert a modification in behavior. You created a seam when you setup injection of your dependency.
One way to take advantage of a seam is to insert some sort of fake. Fake's can be hand-rolled, as in your example, or be created with a tool, like Mockito.
So, a mock is a type of fake, and a fake is often used by taking advantage of a Seam.
As for your tests and the way you broke the dependency, that's pretty much how I would have done it.
Seams
A seam is a place that allows you to modify the behavior without modifying the code.
In your example, the following is an example of an Object seam (if i'm not mistaken). It allows you to pass in a different object without having to change the code. hence it is a type of seam.
public void doSomeProcessing(ParameterSource request) {..}
By making the parameter an abstract type (instead of a concrete class), you have introduced a seam. The seam now allows you to modify the behavior of the method without editing its code - i.e. at the place of invokation, I can pass in a different object and make the method do something else.
Mocks
Now instead of creating your custom fake (creating a subtype of the interface), you could using a Mock framework to do something like this
Mocks also support asserting whether specific methods were called on it, argument matching and other nifty functionality to be consumed by tests. Less test code to maintain. Mocks are primarily used to assert that a specific call is being made to a dependency. In your example, you seem to be in need of a Stub, you just want to return a canned value.
Pardon my rusty JMock..
#Test
public void
the_output_does_not_get_populated_when_the_request_is_empty
() {
Mockery context = new Mockery();
final ParameterSource mockSource = context.mock(ParameterSource.class)
context.checking(new Expectations(){{
oneOf(mockSource).getParameters();
will(returnValue(new string[]{"ParamA","ParamB","ParamC"} );
}});
aBitOfLegacy.populate(mockSource);
assertThat(aBitOfLegacy.output,not(EMPTY));
}
in .Net
var mockSource = new Mock<ParameterSource>();
mockSource.Setup(src => src.GetParameters())
.Returns(new []{"ParamA","ParamB","ParamC"});

Counting method invocations in Unit tests

What is the best way to count method invocations in a Unit Test. Do any of the testing frameworks allow that?
It sounds like you may want to be using the .expects(1) type methods that mock frameworks usually provide.
Using mockito, if you were testing a List and wanted to verify that clear was called 3 times and add was called at least once with these parameters you do the following:
List mock = mock(List.class);
someCodeThatInteractsWithMock();
verify(mock, times(3)).clear();
verify(mock, atLeastOnce()).add(anyObject());
Source - MockitoVsEasyMock
In Mockito you can do something like this:
YourService serviceMock = Mockito.mock(YourService.class);
// code using YourService
// details of all invocations including methods and arguments
Collection<Invocation> invocations = Mockito.mockingDetails(serviceMock).getInvocations();
// just a number of calls of any mock's methods
int numberOfCalls = invocations.size();
Given an example class "RoleRepository" with a single method "getRole(String user)" which would return a role.
Assuming you have declared this object as Mock or Spy and you want to check whether the method getRole(String) is called for once a time.
You would do something like: Mockito.verify(roleRepository, Mockito.times(1)).getRole(Mockito.anyString());
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
#RunWith(MockitoJUnitRunner.class)
public class RoleRepositoryTest {
#Spy
private RoleRepository roleRepository = new RoleRepository();
#Test
public void test() {
roleRepository.getRole("toto");
Mockito.verify(roleRepository, Mockito.times(1)).getRole(Mockito.anyString());
}
public static class RoleRepository {
public String getRole(String user) {
return "MyRole";
}
}
}
You can count number of method invocation by using interface Answer in Mockito.
ConnectionPool mockedConnectionPool = mock(ConnectionPool.class);
final int[] counter = new int[1];
when(mockedConnectionPool.getConnection()).then(new Answer<Connection>() {
#Override
public Connection answer(InvocationOnMock invocation) throws Throwable {
counter[0]++;
return conn;
}
});
// some your code
assertTrue(counter[0] == 1);
Depending on what methods you want to count, you can create a test config, with a #Before advice matching your class / package / method:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
#Aspect
public class MethodCounterAspect {
private int counter = 0 // or inject the Counter object into this aspect
#Pointcut( "execution( * com.sample.your.package.*.*(..) )" )
public void methodsToCount() {}
#Before("methodsToCount()")
public void execute() throws Throwable {
counter++; // or update the counter injected into this aspect..
}
// get the counter
}
You can use vanilla AspectJ or Spring AOP via above or XML configs if you find it easier.
You can create different pointcuts / aspect if you need to.
It sounds like you may want a test spy. See, for example, Mockito.spy().
You've got a few options
1) Add some special code which counts invocations in the function. It will work, but it's not a great solution.
2) After you run your unit tests, check the code coverage. Most coverage tools will count invocations but they are really designed for post-processing.
3) Use a profiler. A profiler will let you count how many times a function is invoked. This is a very manual process so it's not really designed for unit testing.
A better solution would be to check that output is what you expect rather than checking how it works internally.

Categories