Reputation: 6894
I'm unable to verify whether object exists in mocked map and also unable to verify whether register() is called on that object. Below are the errors thrown in the test
Assert.assertNotNull(locationDataMonitor); //Throws assertionError
Mockito.verify(locationDataMonitor, Mockito.times(1)).register()); //org.mockito.exceptions.misusing.NullInsteadOfMockException:
Implementation
public class DataAcquisitionService {
private Map<String, IDataMonitor> dataMonitors;
public DataAcquisitionService (...) {
this.dataMonitors = new ConcurrentHashMap<>();
}
public void doSomething(String id) {
IDataMonitor dataMonitor = null;
if (this.dataMonitors.containsKey(locationId)) {
dataMonitor = this.dataMonitors.get(locationId);
dataMonitor.register();
}
}
}
Test
@RunWith(PowerMockRunner.class)
public class DataAcquisitionServiceTest {
@Mock
private Map<String, IDataMonitor> dataMonitors;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
locationDataMonitors = Mockito.mock(ConcurrentHashMap.class);
this.target = new DataAcquisitionService(..);
}
@Test
public void test_doSomething() {
String id = "id1";
this.target.doSomething(id);
IDataMonitor locationDataMonitor = this.dataMonitors.get(id)
Assert.assertNotNull(locationDataMonitor);
Mockito.verify(locationDataMonitor, Mockito.times(1)).register();
}
}
Upvotes: 0
Views: 1760
Reputation: 184
Looks like you want to hold IDataMonitor
objects in a collection within your service and try to call a method (register()
) on these objects under certain circumstances.
The approach here would be to mock an IDataMonitor
object, put it into the collection (probably by calling an existing public method on your DataAcquisitionService
) and then run the test.
The inner collection in use should be irrelevant for the test.
I can only assume you have a method like this, to get your IDataMonitor
s into the service:
// within DataAcquisitionService
...
public void addMonitor(IDataMonitor monitor) {
this.dataMonitors.put(monitor.getId(), monitor);
}
Then you could do something like this in your test:
private IDataMonitor monitor;
@Before
public void setUp() {
...
this.monitor = Mockito.mock(IDataMonitor.class);
Mockito.when(monitor.getId()).thenReturn("id1");
this.target = new DataAcquisitionService(..);
this.target.addMonitor(monitor); // now monitor is in the map
}
@Test
public void test_doSomething() {
String id = "id1";
// as our monitor mock with "id1" is in the map, it is found and the register() method is called
this.target.doSomething(id);
// verify method call on the mocked monitor
Mockito.verify(this.monitor, Mockito.times(1)).register();
}
Hope this helps!
Upvotes: 1
Reputation: 140467
You only mock objects that need to be controlled.
You should never ever mock simple collection instances. You simply pass around collection objects that carry the content required to make your code under test the expected path. In your case, you could simply pass an empty map to that class. And after invoking the method under test you check if that map contains the required content.
And to verify the content of a map you simply query the map for its content. For example by using the assertThat assert together with the hamcrest is matcher.
But just to be precise: you don't want to write tests that need to know about such implementation details. You should test the public contracts of your methods instead of exposing the fact that you are using a map to hold values.
Finally: it seems that you don't understand what mock objects are actually about. They are mocks that appear to be instances of a certain class. But they absolutely do not know anything about the real class. A mocked map doesn't store keys and values. The only thing that you can do is to specify respectively verify what method calls are expected to happen for that mock object.
Upvotes: 2