Mockito:Java - 未完成的存根检测

时间:2016-06-10 11:49:18

标签: java unit-testing mocking mockito junit4

我一直在与Mockito合作并遇到此错误消息:

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at       com.rbc.rewards.catalogue.service.B2SServicesTest.getProductList_Success(B2SServ icesTest.java:52)

E.g. thenReturn() may be missing.
Examples of correct stubbing:
  when(mock.isOk()).thenReturn(true);
  when(mock.isOk()).thenThrow(exception);
  doThrow(exception).when(mock).someVoidMethod();
Hints:
  1. missing thenReturn()
  2. you are trying to stub a final method, you naughty developer!
  3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed

我已经阅读了有关此问题的Stack Overflow上的两篇帖子,但他们没有详细介绍。我认为这与在模拟中嵌套模拟(从我读到的内容)有关。但是,我没有看到或完全理解人们发布的小片段。

我的测试类如下(省去不必要的代码):

// Mock:  uses Java Reflection in order to create mock objects of each class
@Mock
private Scrapes scrapeS;
@Mock
private SsoS ssoS;
@Mock
private BScrape bScrape;

//@InjectMocks annotation is used to create and inject the mock object
@Mock
private BService bService;


@Before
public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);
}

// Testing:
@Test
public void getProductList_Success() throws Exception{

        when(BService.getProductList("cookie", "6753"))
                .thenReturn(
                scrapeS.scrapePost(new String(),
                        new String(),
                        new HashMap<>(),
                        new bService()));
}

我需要调用的方法:

public List<prodItem> getProdList(String raw_cookie, String catId) throws Exception {
    String url = ssoSetting.getUrls().BProductList();
    String post = "url" + catId +"url";
    BScrape scraper = new BScrape ();
    Map<String, String> postRequest = new HashMap();
    postRequest.put("searchRequestParams", post);
    return scrapeS.scrapePost(url, raw_cookie, postRequest, scraper);
}

我也在使用TutorialsPoint的资源。

它发生在@test方法中,我相信这种嘲弄里面的嘲弄是因为我使用它错了我假设。

从答案(工作)实施后:

@Mock
private SSetting sSetting = new SSetting ();
// Mock:  uses Java Reflection in order to create mock objects and is injected into InjectMocks
@Mock
private ProdItem productItem = new ProdItem ();
@Mock
private sService scrapeService = new sService ();
@Mock
private BScrape bScrape ;

//@InjectMocks annotation is used to create and inject the mock object
@InjectMocks
private BService bService = new BService ();

@Before
public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);
}

// Testing:
@Test
public void getProductList_Success() throws Exception{

    List<ProductItem> retList = new ArrayList<>();
    retList.add(new ProductItem());
    retList.add(new ProductItem());

    //try{
    when(b2SServices.getProductList("cookie", "6753")).thenCallRealMethod();

    //test the add functionality
    when(BService .getProdList("cookie", "6753")).thenReturn(retList);


    }catch(Exception exception){
        System.out.println(exception);
    }
}

2 个答案:

答案 0 :(得分:2)

你是第三种情况:

  

3:你之前正在抄袭另一个模拟人的行为   &#39; thenReturn&#39;指示完成后

这是因为thenReturn从另一个模拟scrapeS.scrapePost调用方法很难确切地说如何解决这个问题因为我需要更多的实现细节但是尝试在when之前构建返回对象并且它不应该&# 39;是另一个模拟的回报。这里有一个很好的解释:https://stackoverflow.com/a/26319364/1121883

这是一个小例子。您的代码类似于play测试。在返回时,您应该在fix测试中提供一个对象,而不是模拟上的调用。

@Test
public void play(){
    A a = mock(A.class);
    B b = mock(B.class);
    when(a.a("input")).thenReturn(b.b("input"));
}

@Test
public void fix(){
    A a = mock(A.class);
    B b = mock(B.class);
    String returnString = "b";
    when(a.a("input")).thenReturn(returnString);
}

static class A{
    String a(String in){
        return "a";
    }
} 

static class B{
    String b(String in){
        return "b";
    }
}

您的代码应该是:

    List<prodItem> retList = new ArrayList<>();
    retList.add(new ProdItem());
    retList.add(new ProdItem());
    when(bService.getProductList("cookie", "6753")).thenReturn(retList);

答案 1 :(得分:1)

代码的(稍微简化的)评估顺序

when(bService.getProductList("cookie", "6753"))
                .thenReturn(
                scrapeS.scrapePost(new String(),
                        new String(),
                        new HashMap<>(),
                        new bService()));

是第一个:

bService.getProductList("cookie", "6753")

第二

when(/*...*/)

第三次

scrapeS.scrapePost(new String(),
                        new String(),
                        new HashMap<>(),
                        new bService())

因此,在尝试模拟bService时,您使用模拟scrapeS

请注意,这根本没有意义。基本上,您目前正在尝试为bService.getProductList提供一个应该使用scrapeS的实现。但是bService是一个模拟,因此没有实现。

如果您希望bServicescrapeS的调用返回相同的对象,则将该对象存储到局部变量中,并在两种方法的thenReturn子句中使用该局部变量。

Object returnValue = /*whatever the return value is*/
when(bService.getProductList("cookie", "6753")).thenReturn(returnValue);
when(scrapeS.scrapePost(new String(), new String(), new HashMap<>(), new bService())).thenReturn(returnValue);