Java 使用 mockito 进行单元测试时抛出 WrongTypeOfReturnValue 异常

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22616450/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 16:53:55  来源:igfitidea点击:

WrongTypeOfReturnValue exception thrown when unit testing using mockito

javaunit-testingmockingtddmockito

提问by Susie

My Test

我的测试

List<Person> myList;

@Test
public void testIsValidPerson() {
    myList = new ArrayList<Person>();

    myList.add(new Person("Tom"));
    when(personDao.get(person)).thenReturn(myList);
    when((personDao.get(person)).isEmpty()).thenReturn(false);//------Exception thrown 

    boolean result = service.isValid("Tom");
    assertFalse(result);
}

Method to be tested:

测试方法:

public boolean isValid(String person){
    personDao = new PersonDao();
    Person personObj = new Person(person);
    return (personDao.get(person).isEmpty())?false : true;      
}

Exception thrown:

抛出异常:

org.mockito.exceptions.misusing.WrongTypeOfReturnValue: 
Boolean cannot be returned by get()
get() should return List
***
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
1. This exception *might* occur in wrongly written multi-threaded tests.
   Please refer to Mockito FAQ on limitations of concurrency testing.
2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies - 
   - with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.

My Second approach using spy:

我使用间谍的第二种方法:

public void testIsValidPerson() {
    myList = new ArrayList<Person>();

    myList.add(new Person("Tom"));
    when(personDao.get(person)).thenReturn(myList);

    List<Person> mylist = personDao.get(person);
    List spy = spy(mylist);

    doReturn(false).when(spy.isEmpty());//------exception thrown

    boolean result = service.isValid("Tom");
    assertFalse(result);
}

This gives me the following exception:

这给了我以下异常:

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at com.PersonTest.testIsValid(PersonTest.java:76)

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!

Third appraoch:

第三招:

@Test
public void testIsValidPerson() {
    myList = new ArrayList<Person>();

    myList.add(new Person("Tom"));
    when(personDao.get(person)).thenReturn(myList);

    boolean result = service.isValid("Tom");//--------Throws null pointer exception
    assertFalse(result);
}

public boolean isValid(String person){
    personDao = new PersonDao();
    Person personObj = new Person(person);
    return (personDao.get(person).isEmpty())?false : true;  //----throws NPE    
}

Fourth Approach:throws Null pointer exception

方法四:抛出空指针异常

@Test
public void testIsValidPerson() {
    List<Person> mockedList = mock(List.class);
    when(personDao.get(person)).thenReturn(mockedList);
    when(personDao.get(person)).isEmpty().thenReturn(false);
    boolean result = service.isValid("Tom");//--------Throws null pointer exception
    assertFalse(result);
}

public boolean isValid(String person){
    personDao = new PersonDao();
    Person personObj = new Person(person);
    return (personDao.get(person).isEmpty())?false : true;  //----throws NPE    
}

Fifth approach:Also gives NPE.

第五种方法:也给NPE。

The get method of personDao accesses the database and the NPE is thrown when getting a connection to the DB. But it doesn't give NPE the first time around when I get an empty list back. I get NPE in the second call from service.isValid()

personDao 的 get 方法访问数据库,在获取到数据库的连接时抛出 NPE。但是当我得到一个空列表时,它并没有第一次给 NPE。我在第二个电话中接到了 NPEservice.isValid()

@Test
public void testIsValidPerson() {
    when(personDao.get(person)).thenReturn(new ArrayList<Person>());
    List tempList=personDao.get(person);//----I get empty tempList---No NPE
    boolean result = service.isValid("Tom");//--------Throws null pointer exception
    assertFalse(result);
}

Approach 6:

方法六:

@Test
public void testIsValid() {
    personList = new ArrayList<Person>();
    Person person = new Person("Tom");
    personList.add(person);
    when(personDao.get(person)).thenReturn(personList);//-------Uses same person object

    boolean result = service.isValid(person);//------------Uses same person object
    assertTrue(result);
}

And I changed my method signature from(so that the test and the method under test would use the same value).

我改变了我的方法签名(这样测试和被测方法将使用相同的值)。

public boolean isValid(String name)

to

public boolean isValid(Person person)

回答by Dawood ibn Kareem

The line when((personDao.get(person)).isEmpty()).thenReturn(false);makes no sense, because personDao.get(person)isn't a mock. It's just myList, because you stubbed it that way on the line above. So this is exactly the same as doing when(myList.isEmpty()).thenReturn(false);- but you can't stub this because there's no mock here.

这条线when((personDao.get(person)).isEmpty()).thenReturn(false);没有意义,因为personDao.get(person)不是模拟。只是myList,因为您在上面的行中以这种方式存根。所以这和做的完全一样when(myList.isEmpty()).thenReturn(false);- 但你不能存根,因为这里没有模拟。

回答by anttix

Basically you do not have enough mocks. You are attempting to mock an isEmptymethod of a Listreturned by a mock object. You have a mock object, but you do not make the mock object return a mock list so you could mock the methods of a mock list ...

基本上你没有足够的模拟。您正在尝试模拟模拟对象返回的 aisEmpty方法List。你有一个模拟对象,但你没有让模拟对象返回一个模拟列表,所以你可以模拟一个模拟列表的方法......

One thing I fail to understand though is why are you attempting to make a list that has elements, but returns true for isEmpty

我不明白的一件事是为什么你试图制作一个包含元素的列表,但返回 true isEmpty

If you need to test how your code behaves when it gets an empty list, just make an empty list. This way isEmptywill automatically return false.

如果您需要测试代码在获取空列表时的行为方式,只需创建一个空列表即可。这种方式isEmpty会自动返回false。

when(personDao.get(person)).thenReturn(new ArrayList<Person>());