【问题标题】:Mockito UnfinishedStubbingException when mocking multiple times多次模拟时Mockito UnfinishedStubbingException
【发布时间】:2020-02-27 19:42:46
【问题描述】:

我想在我的 Invoice 类中存根方法 generateReferenceNumber():

public class Invoice {

    private String id;
    private String referenceNumber;
    private Date issueDate;
    private PaymentMethod paymentMethod;
    private Date paymentDate;
    private String shopId;
    private List<InvoiceGroupItem> groupItems;
    private InvoiceStatus status;

    public void moveToNextState() {
        status = status.nextState();
    }

    public void generateReferenceNumber() {
        if (referenceNumber != null) {
            return;
        }

        referenceNumber = new InvoiceReference().createNew(issueDate).toString();
    }
}

此对象用于我要测试的服务。为此,我需要多张发票。所以我写了以下代码:

private Stream<Invoice> buildApprovedInvoice() {
    val approvedInvoices = new ArrayList<Invoice>();

    for (int i = 0; i < 10; i++) {
        val invoice = Invoice.builder().build();
        val spy = spy(invoice);

        doAnswer(invocation -> {
            final Invoice mock = (Invoice) invocation.getMock();
            mock.setReferenceNumber("Invoice reference number");
            return null;
        }).when(spy).generateReferenceNumber();

        approvedInvoices.add(spy);
    }

    return approvedInvoices.stream();
}

当我执行测试时,出现以下错误:

org.mockito.exceptions.misusing.UnfinishedStubbingException: 此处检测到未完成的存根: -> 在 com.coruscant.core.services.invoice.InvoiceSendingServiceTest.sendInvoices(InvoiceSendingServiceTest.java:54)

例如thenReturn() 可能会丢失。正确的存根示例: 当(模拟。isOk())。然后返回(真); when(mock.isOk()).thenThrow(异常); doThrow(exception).when(mock).someVoidMethod();

有人知道为什么吗?

谢谢。

【问题讨论】:

标签: java mockito stub spy


【解决方案1】:

您不需要模拟 Invoice 来测试它。或者,如果是单元测试,您可以模拟 InvoiceReference。如果是集成测试:

class Test {

   private Invoice invoice;

   @BeforeEach
   void setUp() {
      invoice - new Invoice();
   }
   @Test
   void shouldSetReferenceNumber_WhenReferenceNumberEqualsNull() {
      invoice.setIssueDate(new Date());
      invoice.generateReferenceNumber();
      assertThat(invoice).hasFieldWithValue("referenceNumber", expectingValue);
   }

   @Test
   void shouldNotSetReferenceNumber_WhenReferenceNumberIsNotEqualsNull() {
      invoice.setReferenceNumber("test-reference-number");
      invoice.generateReferenceNumber();
      assertThat(invoice).hasFieldWithValue("referenceNumber", "test-reference-number");
   }
}

单元测试(模拟 InvoiceReference):

public class Invoice {

    private String id;
    private String referenceNumber;
    private Date issueDate;
    private PaymentMethod paymentMethod;
    private Date paymentDate;
    private String shopId;
    private List<InvoiceGroupItem> groupItems;
    private InvoiceStatus status;

    public void moveToNextState() {
        status = status.nextState();
    }

    public void generateReferenceNumber() {
        if (referenceNumber != null) {
            return;
        }

        getInvoiceReference().createNew(issueDate).toString(); 
    }

   public InvoiceReference getInvoiceReference() {
      return new InvoiceReference();
   }
}

class Test {

   private Invoice invoice;
   @Mock
   private InvoiceReference invoiceReference;

   @BeforeEach
   void setUp() {
      invoice = new Invoice();
      MockitoAnnotations.initMocks(this);
      when(invoiceReference.createNew(any(Date.class)).thenReturn("test-reference-number");
   }

   @Test
   void shouldSetReferenceNumber_WhenReferenceNumberEqualsNull() {
      invoice.setIssueDate(new Date());
      invoice.generateReferenceNumber();
      assertThat(invoice).hasFieldWithValue("referenceNumber", "test-reference-number");
   }

   @Test
   void shouldNotSetReferenceNumber_WhenReferenceNumberIsNotEqualsNull() {
      invoice.setReferenceNumber("different_reference_number");
      invoice.generateReferenceNumber();
      assertThat(invoice).hasFieldWithValue("referenceNumber", "different_reference_number");
   }
}

【讨论】:

  • 我真的不知道如何模拟 InvoiceReference,因为我正在调用 new InvoiceReference()。你能解释一下吗?
  • 嗯,我明白了,但我真的不喜欢必须构建一个 InvoiceReference 吸气剂。我的帖子更多地是关于为什么我对 Mockito 的 doAnswer() 的使用不正确。但感谢您的帮助。
  • Alexandre Liscia 然后只使用第一个解决方案(不模拟 InvoiceReference)
  • 您能否解释一下为什么这不起作用?而且,我不想测试 Invoice,而是使用它的服务。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-29
  • 2014-06-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多