【问题标题】:Testing in Spring project - injecting repository into service with Mockito在 Spring 项目中进行测试 - 使用 Mockito 将存储库注入服务
【发布时间】:2018-07-26 07:06:13
【问题描述】:

我正在尝试了解如何在 Spring 项目中使用 Mockito,但我对以下问题有些困惑:

我即将使用真实的(内存中)存储库测试服务。我正在嘲笑该服务正在使用的所有其他对象。如果我理解正确,使用@Mock 注释对象将被嘲笑,@Spy 将使用真实对象,而@InjectMocks 将“自动装配”这些注释对象。但是,我想我误解了@Spy,因为以下代码不起作用(似乎插入了一个模拟对象,既没有数据库交互,也没有出现NullPointerException):

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

    @Spy
    @Autowired
    private UserRepository userRepository;

    @Mock
    private MessageService messageService;

    @InjectMocks
    private UserService userService = new UserServiceImpl();

    @Test
    public void testUserRegistration() {
        userService.registerUser("test@test.test");

        Assert.assertEquals("There is one user in the repository after the first registration.", 1, userRepository.count());
    }
}

如果我删除 @Spy 注释并使用反射将存储库插入服务中,它可以工作:

ReflectionTestUtils.setField(userService, "userRepository", userRepository);

这似乎很不方便,我很确定@Spy 就是为了这样做。谁能指出我遗漏/误解的内容?

编辑:还有一件事 - 使用 @Spy 注释我在保存时没有得到 NullPointerException,但似乎插入了一个模拟对象而不是真正的存储库。

编辑 2: 我认为这是我困惑的答案:

SpringBoot Junit bean autowire

【问题讨论】:

  • 为什么你有 Autowired Spy?你能扩展一下“不工作”吗?
  • 很确定您应该在您的存储库上方使用@Mock
  • 如果可行的话,最好使用构造函数注入正是因为这个原因——你不需要 Spring 进行这个测试,可以简单地创建一个模拟并将其传递给new UserServiceImpl(mockUserRepository)
  • @chrylis 这意味着我必须修改所有服务,因为到处都在使用字段注入,我想避免这种情况。
  • @ThomasWithers 我正在尝试使用内存数据库进行测试,Mock 不会做我想要的,对吗?

标签: java spring testing mockito


【解决方案1】:

问题是你可能@AutowiredUserService 中的一些服务/存储库像这样:

public class UserServiceImpl() {

  @Autowired
  private UserRepository userRepository;
  @Autowired
  private MessageService messageService;

  // ... all the stuff
}

Mockito 尝试通过不可用的构造函数或设置器注入模拟。尝试重新设计您的类UserServiceImpl,使其具有如下构造函数:

public class UserServiceImpl() {

  private final UserRepository userRepository;
  private final MessageService messageService;

  @Autowired
  public UserServiceImpl(UserRepository userRepository, MessageService messageService) {
    this.userRepository = userRepository;
    this.messageService = messageService;
  }

然后,您可以使用这些模拟使用构造函数实例化@Before 中的服务。

【讨论】:

  • 所以顺便说一下,测试中存储库上的@Spy@Autowired 注释是正确的,我唯一的问题是字段自动装配?
  • 如果您在配置中的测试上下文中设置内存数据库,那么我看不到在存储库上使用 @Spy 的理由,因为它已经是真实数据库的模拟。是的,我认为唯一的问题是字段自动装配而不是构造函数/设置器。此外,我强烈建议使用构造函数注入。
  • 另外,现在我发现您在@Before 中缺少MockitoAnnotations.initMocks(this)
  • 我实际上错过了@MockBean注解的存在,基本上我想通过组合一些来手动完成。 :)
  • 此外,如果我尝试尽可能多地从测试中排除 Spring 部件并使用 MockitoJUnitRunner 而不是 SpringRunner,如果我是正确的,我将不需要注意这些。
猜你喜欢
  • 1970-01-01
  • 2019-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-20
  • 2019-03-20
  • 2015-06-23
  • 1970-01-01
相关资源
最近更新 更多