Java 多次模拟时,Mockito UnfinishedStubbingException

Java 多次模拟时,Mockito UnfinishedStubbingException,java,mockito,stub,spy,Java,Mockito,Stub,Spy,我想在发票类中存根Method GenerateReferenceEnumber(): public class Invoice { private String id; private String referenceNumber; private Date issueDate; private PaymentMethod paymentMethod; private Date paymentDate; private String shopI

我想在发票类中存根Method GenerateReferenceEnumber():

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();
    }
}
公共类发票{
私有字符串id;
私有字符串引用编号;
非公开发行日期;
私人付费方式付费方式;
私人日期付款日期;
私人字符串shopId;
私人物品清单;
私人发票状态;
public void moveToNextState(){
status=status.nextState();
}
public void generateReferenceNumber(){
if(referenceNumber!=null){
回来
}
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();
}
私有流buildApprovedInvoice(){
val approvedInvoices=新的ArrayList();
对于(int i=0;i<10;i++){
val发票=发票.builder().build();
val spy=spy(发票);
doAnswer(调用->{
最终发票模拟=(发票)调用.getMock();
mock.setReferenceNumber(“发票参考号”);
返回null;
}).when(spy).GenerateReferenceEnumber();
批准的发票。添加(间谍);
}
返回已批准的发票。stream();
}
当我执行测试时,我得到以下错误:

org.mockito.exceptions.misusing.unfinishedstubingexception: 此处检测到未完成的存根: ->在com.coroscan.core.services.invoice.invoicessendingservicetest.sendvoices(invoicessendingservicetest.java:54)

例如,可能缺少return()。正确的短截线示例: when(mock.isOk())。然后返回(true); when(mock.isOk()).thenthow(异常); doThrow(异常).when(模拟).someVoidMethod()

有人知道为什么吗


谢谢。

您不需要模拟发票来测试它。或者,如果是单元测试,您可以模拟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");
   }
}
单元测试(模拟发票参考):

公共类发票{
私有字符串id;
私有字符串引用编号;
非公开发行日期;
私人付费方式付费方式;
私人日期付款日期;
私人字符串shopId;
私人物品清单;
私人发票状态;
public void moveToNextState(){
status=status.nextState();
}
public void generateReferenceNumber(){
if(referenceNumber!=null){
回来
}
getInvoiceReference().createNew(issueDate.toString();
}
公共发票引用getInvoiceReference(){
返回新的InvoiceReference();
}
}
课堂测试{
私人发票;
@嘲弄
私人发票参考发票参考;
@之前
无效设置(){
发票=新发票();
initMocks(this);
when(invoiceReference.createNew(any(Date.class))。然后返回(“测试参考号”);
}
@试验
当ReferenceEnumbereQualsNull()时,void应设置ReferenceNumber\u{
发票。setIssueDate(新日期());
invoice.GenerateReferenceEnumber();
资产(发票).hasFieldWithValue(“参考编号”、“测试参考编号”);
}
@试验
当ReferenceEnumberisNoteQualsNull()时,void不应设置ReferenceNumber\u{
发票.设置参考编号(“不同的参考编号”);
invoice.GenerateReferenceEnumber();
资产(发票).hasFieldWithValue(“参考编号”、“不同参考编号”);
}
}

当我调用new InvoiceReference()时,我真的不知道如何模拟InvoiceReference。你能解释一下吗?嗯,我明白了,但我可以,我真的不想构建一个InvoiceReference getter。我的帖子更多的是关于我为什么要使用Mockito的doAnswer()是不正确的。但是谢谢你的帮助。Alexandre Liscia然后只使用第一个解决方案(没有模仿InvoiceReference)你能解释一下为什么这不起作用吗?还有,我不想测试Invoice,但想测试一个使用它的服务。我很确定异常不是来自你问题中显示的代码。你能提供一个生成异常的方法吗?
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");
   }
}