Тестирование Mockito junit не работает - бобы, издевающиеся над @mockBean, равны нулю - PullRequest
0 голосов
/ 02 ноября 2019

Я пробую Mockito для издевательств и юнит-тестирования.

Попытка смоделировать боб с автопроводкой, используя @MockBean. Но bean-компонент имеет нулевое значение во время выполнения.

Класс проверяется.

@Service
public class UserServiceImpl  {

  @Autowired
  GenericRestClient restClient;

  @Autowired
  RequestMapper requestMapper;

  @Autowired
  ResponseMapper responseMapper;

  @Override
  public List<User> findUsers(RRequest requestBody,
      String index) throws HostException {
List<User> users= 
requestMapper.mapRequest("test");
// ...doing something
return users;
}

Тестовый класс:


import static org.junit.Assert.assertNotNull;

import java.util.ArrayList;
import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.boot.test.mock.mockito.MockBean;

@RunWith(MockitoJUnitRunner.class)

public class UserServiceImplTest {

    @MockBean
    GenericRestClient restClient;

    @MockBean
    RequestMapper requestMapper;

    @MockBean
    ResponseMapper responseMapper;

    @InjectMocks
    UserServiceImpl userService;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);

    }

    @Test
    public void testFindUsers() {
List<Users> users = null;
        Mockito.when(requestMapper.mapRequest("test"))
        .thenReturn(users); 
        assertNull(users);      
    }
}

Ошибка:

java.lang.NullPointerException
    at test.my.code.UserServiceImplTest.testFindUsers(UserServiceImplTest.java:10)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.mockito.internal.runners.DefaultInternalRunner$1.run(DefaultInternalRunner.java:79)
    at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:85)
    at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:39)
    at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:163)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)


Я отладил, NullPointerException из-за requestMapper (издевался с использованием MockBeannull.)

Что не так с этим кодом?

Ответы [ 2 ]

1 голос
/ 03 ноября 2019

В отличие от @abinmichael, я не предлагаю использовать Spring Runner для запуска этого теста. Ваш тест является модульным тестом, и запуск Spring (создание контекста приложения) является очень дорогой операцией, более подходящей для интеграционного тестирования.

Я не эксперт по mockito, но я считаю, что вам следует немного изменить рефакторингUserServiceImpl, чтобы зависимости стали видны:

@Service
public class UserServiceImpl  {


 private final GenericRestClient restClient;
 private final RequestMapper requestMapper;
 private final ResponseMapper responseMapper;

 @Autowired // in recent spring version, this annotation can be omitted 
 public UserServiceImpl(GenericRestClient restClient, RequestMapper requestMapper, ResponseMapper responseMapper) {
    this.restClient = restClient;
    this.requestMapper = requestMapper;
    this.responseMapper = responseMapper;    
 }
 ...

При таком подходе больше нет необходимости в @InjectMocks:

@RunWith(MockitoJUnitRunner.class)

public class UserServiceImplTest {

@Mock
GenericRestClient restClient;

@Mock
RequestMapper requestMapper;

@Mock
ResponseMapper responseMapper;


UserServiceImpl userService;

@Before 
public void init() {
  userService = new UserServiceImpl(restClient, requestMapper, responseMapper);
}

....
}

Если вы настаиваете на использовании полейвпрыск, прочитайте Принятый ответ , чтобы получить больше информации о том, как @InjectMocks работает. Может быть, у вас нет «закрытого» модификатора доступа, может быть, у вас есть некоторая смесь между инжектором «Конструктор» и «Инъекция поля», и @InjectMocks не поддерживает оба одновременно

0 голосов
/ 02 ноября 2019

Можете ли вы попробовать запустить тест после изменения на

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceImplTest {

Javadoc https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/mock/mockito/MockBean.html состояния

 @Target(value={TYPE,FIELD})
 @Retention(value=RUNTIME)
 @Documented
 @Repeatable(value=MockBeans.class)
public @interface MockBean

Аннотация, которую можно использовать для добавления макетов в SpringApplicationContext. Может использоваться как аннотация уровня класса или для полей либо в классах @Configuration, либо в тестовых классах, которые являются @RunWith SpringRunner.

...