【问题标题】:test void method inside abstract anonymous class with mockito使用 mockito 在抽象匿名类中测试 void 方法
【发布时间】:2017-12-12 00:54:09
【问题描述】:

我无法测试抽象类实例中的方法。我已经尝试了几种方法,想知道是否可以这样做。抽象类的内容可以看下面的链接。

Jacoco Class Report

下面是我尝试测试上图中的案例的 JUnit 和 Mockito 测试。

@RunWith(MockitoJUnitRunner.class)
public class PahoRxMqttCallbackTest {

  @Test
  public void whenConnectionLostOccurs() {
    PahoRxMqttCallback rxMqttCallback = mock(PahoRxMqttCallback.class);
    assertThat(rxMqttCallback).isNotNull();

    PahoRxMqttException exception = new PahoRxMqttException(
        new MqttException(MqttException.REASON_CODE_CONNECTION_LOST));

    ArgumentCaptor<Throwable> onConnectionLostCauseArgumentCaptor = ArgumentCaptor.forClass(Throwable.class);

    rxMqttCallback.connectionLost(exception);

    verify(rxMqttCallback).connectionLost(onConnectionLostCauseArgumentCaptor.capture());

    assertThat(onConnectionLostCauseArgumentCaptor.getValue()).isNotNull();
    assertThat(onConnectionLostCauseArgumentCaptor.getValue()).isInstanceOf(PahoRxMqttException.class);
    assertThat(onConnectionLostCauseArgumentCaptor.getValue()).hasCauseInstanceOf(MqttException.class);
    assertThat(onConnectionLostCauseArgumentCaptor.getValue()).isEqualTo(exception);
  }

  @Test
  public void whenConnectCompleteOccurs() {
    PahoRxMqttCallback rxMqttCallback = mock(PahoRxMqttCallback.class);
    assertThat(rxMqttCallback).isNotNull();

    boolean reconnect = true;
    String brokerUri = "tcp://localhost:1883";

    ArgumentCaptor<Boolean> onConnectCompleteReconnectArgumentCaptor = ArgumentCaptor.forClass(Boolean.class);
    ArgumentCaptor<String> onConnectCompleteServerUriArgumentCaptor = ArgumentCaptor.forClass(String.class);

    rxMqttCallback.connectComplete(reconnect, brokerUri);

    verify(rxMqttCallback).connectComplete(
        onConnectCompleteReconnectArgumentCaptor.capture(),
        onConnectCompleteServerUriArgumentCaptor.capture());

    assertThat(onConnectCompleteReconnectArgumentCaptor.getValue()).isNotNull();
    assertThat(onConnectCompleteReconnectArgumentCaptor.getValue()).isEqualTo(reconnect);
    assertThat(onConnectCompleteServerUriArgumentCaptor.getValue()).isNotNull();
    assertThat(onConnectCompleteServerUriArgumentCaptor.getValue()).isEqualTo(brokerUri);
  }

  @Test
  public void whenDeliveryCompleteOccurs() {
    PahoRxMqttCallback rxMqttCallback = mock(PahoRxMqttCallback.class);
    assertThat(rxMqttCallback).isNotNull();

    IMqttDeliveryToken deliveryToken = mock(IMqttDeliveryToken.class);
    assertThat(deliveryToken).isNotNull();

    RxMqttToken rxMqttToken = new PahoRxMqttToken(deliveryToken);

    //ArgumentCaptor<IMqttDeliveryToken> onDeliveryCompleteTokenArgumentCaptor = ArgumentCaptor.forClass(IMqttDeliveryToken.class);
    ArgumentCaptor<RxMqttToken> onDeliveryCompleteRxTokenArgumentCaptor = ArgumentCaptor.forClass(RxMqttToken.class);

    //rxMqttCallback.deliveryComplete(deliveryToken);
    rxMqttCallback.deliveryComplete(rxMqttToken);

    /*
     * Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
     * Mocking methods declared on non-public parent classes is not supported.
     */
    //verify(rxMqttCallback).deliveryComplete(onDeliveryCompleteTokenArgumentCaptor.capture());
    verify(rxMqttCallback).deliveryComplete(onDeliveryCompleteRxTokenArgumentCaptor.capture());

    //assertThat(onDeliveryCompleteTokenArgumentCaptor.getValue()).isNotNull();
    //assertThat(onDeliveryCompleteTokenArgumentCaptor.getValue()).isExactlyInstanceOf(IMqttDeliveryToken.class);
    //assertThat(onDeliveryCompleteTokenArgumentCaptor.getValue()).isEqualTo(deliveryToken);

    assertThat(onDeliveryCompleteRxTokenArgumentCaptor.getValue()).isNotNull();
    assertThat(onDeliveryCompleteRxTokenArgumentCaptor.getValue()).isExactlyInstanceOf(PahoRxMqttToken.class);
    assertThat(onDeliveryCompleteRxTokenArgumentCaptor.getValue()).isEqualTo(rxMqttToken);
  }

  //@Test
  public void whenMessageArrived() throws Exception {
    PahoRxMqttCallback rxMqttCallback = mock(PahoRxMqttCallback.class);
    assertThat(rxMqttCallback).isNotNull();

    String topic = "topic";
    MqttMessage message = new MqttMessage();

    ArgumentCaptor<String> onMessageArrivedTopicArgumentCaptor = ArgumentCaptor.forClass(String.class);
    ArgumentCaptor<MqttMessage> onMessageArrivedMessageArgumentCaptor = ArgumentCaptor.forClass(MqttMessage.class);

    rxMqttCallback.messageArrived(topic, message);

    /*
     * Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
     * Mocking methods declared on non-public parent classes is not supported.
     */
    verify(rxMqttCallback).messageArrived(onMessageArrivedTopicArgumentCaptor.capture(), onMessageArrivedMessageArgumentCaptor.capture());

    assertThat(onMessageArrivedTopicArgumentCaptor.getValue()).isNotNull();
    assertThat(onMessageArrivedTopicArgumentCaptor.getValue()).isEqualTo(topic);

    assertThat(onMessageArrivedMessageArgumentCaptor.getValue()).isNotNull();
    assertThat(onMessageArrivedMessageArgumentCaptor.getValue()).isEqualTo(message);
  }

}

即使在网上搜索后我也真的无法做到。非常感谢您的帮助。

更新

我能够执行测试并涵盖 Jacoco 显示的所有警报。但为此,我必须为抽象类创建一个实现,而不是使用匿名类。如以下链接所示

Jacoco Class Report 2

更新的单元测试:

@RunWith(MockitoJUnitRunner.class)
public class PahoRxMqttCallbackTest {

  @Test
  public void whenConnectionLostOccurs() {
    PahoRxMqttCallback rxMqttCallback = spy(PahoRxMqttCallback.create(cause -> {}, (recon, uri) -> {}, t -> {}));

    PahoRxMqttException exception = new PahoRxMqttException(
        new MqttException(MqttException.REASON_CODE_CONNECTION_LOST));

    ArgumentCaptor<Throwable> onConnectionLostCauseArgumentCaptor = ArgumentCaptor.forClass(Throwable.class);

    rxMqttCallback.connectionLost(exception);

    verify(rxMqttCallback).connectionLost(onConnectionLostCauseArgumentCaptor.capture());

    assertThat(onConnectionLostCauseArgumentCaptor.getValue()).isNotNull();
    assertThat(onConnectionLostCauseArgumentCaptor.getValue()).isInstanceOf(PahoRxMqttException.class);
    assertThat(onConnectionLostCauseArgumentCaptor.getValue()).hasCauseInstanceOf(MqttException.class);
    assertThat(onConnectionLostCauseArgumentCaptor.getValue()).isEqualTo(exception);
  }

  @Test
  public void whenConnectCompleteOccurs() {
    PahoRxMqttCallback rxMqttCallback = spy(PahoRxMqttCallback.create(cause -> {}, (r, u) -> {}, t -> {}));

    boolean reconnect = true;
    String brokerUri = "tcp://localhost:1883";

    ArgumentCaptor<Boolean> onConnectCompleteReconnectArgumentCaptor = ArgumentCaptor.forClass(Boolean.class);
    ArgumentCaptor<String> onConnectCompleteServerUriArgumentCaptor = ArgumentCaptor.forClass(String.class);

    rxMqttCallback.connectComplete(reconnect, brokerUri);

    verify(rxMqttCallback).connectComplete(
        onConnectCompleteReconnectArgumentCaptor.capture(),
        onConnectCompleteServerUriArgumentCaptor.capture());

    assertThat(onConnectCompleteReconnectArgumentCaptor.getValue()).isNotNull();
    assertThat(onConnectCompleteReconnectArgumentCaptor.getValue()).isEqualTo(reconnect);
    assertThat(onConnectCompleteServerUriArgumentCaptor.getValue()).isNotNull();
    assertThat(onConnectCompleteServerUriArgumentCaptor.getValue()).isEqualTo(brokerUri);
  }

  @Test
  public void whenDeliveryCompleteOccurs() {
    PahoRxMqttCallback rxMqttCallback = spy(PahoRxMqttCallback.create(cause -> {}, (r, u) -> {}));

    IMqttDeliveryToken deliveryToken = new MqttDeliveryToken();

    RxMqttToken rxMqttToken = new PahoRxMqttToken(deliveryToken);

    ArgumentCaptor<IMqttDeliveryToken> onDeliveryCompleteTokenArgumentCaptor = ArgumentCaptor.forClass(IMqttDeliveryToken.class);
    ArgumentCaptor<RxMqttToken> onDeliveryCompleteRxTokenArgumentCaptor = ArgumentCaptor.forClass(RxMqttToken.class);

    rxMqttCallback.deliveryComplete(deliveryToken);
    rxMqttCallback.deliveryComplete(rxMqttToken);

    verify(rxMqttCallback).deliveryComplete(onDeliveryCompleteTokenArgumentCaptor.capture());
    verify(rxMqttCallback, times(2)).deliveryComplete(onDeliveryCompleteRxTokenArgumentCaptor.capture());

    assertThat(onDeliveryCompleteTokenArgumentCaptor.getValue()).isNotNull();
    assertThat(onDeliveryCompleteTokenArgumentCaptor.getValue()).isExactlyInstanceOf(MqttDeliveryToken.class);
    assertThat(onDeliveryCompleteTokenArgumentCaptor.getValue()).isEqualTo(deliveryToken);

    assertThat(onDeliveryCompleteRxTokenArgumentCaptor.getValue()).isNotNull();
    assertThat(onDeliveryCompleteRxTokenArgumentCaptor.getValue()).isExactlyInstanceOf(PahoRxMqttToken.class);
    assertThat(onDeliveryCompleteRxTokenArgumentCaptor.getValue()).isEqualTo(rxMqttToken);
  }

  @Test
  public void whenMessageArrived() throws Exception {
    PahoRxMqttCallback rxMqttCallback = spy(PahoRxMqttCallback.create(cause -> {}, (r, u) -> {}, t -> {}));

    String topic = "topic";
    MqttMessage message = new MqttMessage();

    ArgumentCaptor<String> onMessageArrivedTopicArgumentCaptor = ArgumentCaptor.forClass(String.class);
    ArgumentCaptor<MqttMessage> onMessageArrivedMessageArgumentCaptor = ArgumentCaptor.forClass(MqttMessage.class);

    rxMqttCallback.messageArrived(topic, message);

    verify(rxMqttCallback).messageArrived(onMessageArrivedTopicArgumentCaptor.capture(), onMessageArrivedMessageArgumentCaptor.capture());

    assertThat(onMessageArrivedTopicArgumentCaptor.getValue()).isNotNull();
    assertThat(onMessageArrivedTopicArgumentCaptor.getValue()).isEqualTo(topic);

    assertThat(onMessageArrivedMessageArgumentCaptor.getValue()).isNotNull();
    assertThat(onMessageArrivedMessageArgumentCaptor.getValue()).isEqualTo(message);
  }

}

【问题讨论】:

  • 您在此处发布了多个测试,但您忘记向我们展示您要测试的抽象类和方法。另外,这些测试中的哪一个应该测试这个方法?
  • @alfasin 抽象类表示在可以通过上面的链接访问的图像中。 (雅可可班报告)。但是,如果您愿意,我可以通过完整放置课程内容来更新帖子。基本上,我想测试通过链接可用的图像中标记为红色的所有内容,特别是从第 50 行开始到第 70 行结束的方法。为此,我创建了测试方法:whenConnectionLostOccurs、whenConnectCompleteOccurs 和whenDeliveryComplete 分别发生。
  • 在提问之前,您应该先学习一个简单的 Mockito 教程。
  • @tkruse 感谢您的评论,但您应该温和一点。我已经阅读了 Mockito。

标签: java junit mockito abstract-class anonymous-class


【解决方案1】:

你永远不会实例化类,只会模拟类。

 PahoRxMqttCallback rxMqttCallback = mock(PahoRxMqttCallback.class);

mock 不是真正的类,只是一个伪造的副本。

你应该这样做

 PahoRxMqttCallback rxMqttCallback = new PahoRxMqttCallback();

 PahoRxMqttCallback rxMqttCallback = spy(new PahoRxMqttCallback());

【讨论】:

  • 我尝试使用真实对象,但 Mockito 的验证方法抱怨它(org.mockito.exceptions.misusing.NotAMockException:传递给 verify() 的参数是类型并且不是模拟)。所以,让我们尝试使用 spy() 方法。使用这种方法运行测试,但 Jacoco 生成的报告与我使用 Mockito 的模拟方法时的警告相同。你的回答没有错,但这不是我为解决我的问题而必须做的完整解决方案。
猜你喜欢
  • 1970-01-01
  • 2010-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多