如何在模拟时从Map获取元素

时间:2018-03-11 05:39:15

标签: java junit mockito

我无法验证对象是否存在于模拟映射中,也无法验证是否在该对象上调用了register()。 以下是测试中引发的错误

Assert.assertNotNull(locationDataMonitor); //Throws assertionError
Mockito.verify(locationDataMonitor, Mockito.times(1)).register()); //org.mockito.exceptions.misusing.NullInsteadOfMockException: 

实施

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();
    }
  }
}

测试

@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();  
   }
}

2 个答案:

答案 0 :(得分:2)

您只能模拟需要控制的对象。

你永远不应该模拟简单的集合实例。您只需传递包含使测试中的代码成为预期路径所需内容的集合对象。在您的情况下,您可以简单地将空地图传递给该类。在调用测试方法后,检查该映射是否包含所需内容。

要验证地图的内容,您只需在地图中查询其内容即可。例如,通过将 assertThat 断言与hamcrest一起使用匹配器。

但准确地说:您不想编写需要了解此类实施细节的测试。您应该测试方法的公共合同,而不是暴露您使用地图来保存值的事实。

最后:您似乎并不了解模拟对象的实际内容。它们是模拟,似乎是某个类的实例。但他们绝对不了解真正的班级。模拟的地图不存储键和值。您唯一能做的就是分别指定验证该模拟对象预期会发生什么样的方法调用。

答案 1 :(得分:1)

您希望在服务中的集合中保留IDataMonitor个对象,并尝试在某些情况下调用这些对象的方法(register())。

这里的方法是模拟IDataMonitor对象,将其放入集合中(可能通过调用DataAcquisitionService上的现有公共方法),然后运行测试。

使用中的内部集合应该与测试无关。

我只能假设你有这样的方法,让你的IDataMonitor进入服务:

  // within DataAcquisitionService
  ...
  public void addMonitor(IDataMonitor monitor) {
    this.dataMonitors.put(monitor.getId(), monitor);
  }

然后你可以在测试中做这样的事情:

    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(); 
    }

希望这有帮助!