mockito不会在实际方法中嘲笑

时间:2017-12-06 18:43:06

标签: java unit-testing mocking mockito

我在下面的测试中模拟了AuthService,并将authService.checkAuthority(any(UserAuthority.class))设置为“true”。它实际上已经设置但在实际方法(authService.checkAuthority(UserAuthority.COMMENT_ACCESS))中它将值变为false。

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(ApplicationRunner.class)
@WebAppConfiguration
@Transactional
public class TagsTest extends BaseWebTest {
    @Autowired
    private TagService tagService;
    @Autowired
    private TagRepository repository;
    UserDetailsDto currentUser;
    @Autowired
    protected AuthService authService;
    @Autowired
    protected StringRedisTemplate stringRedisTemplate;
    @Autowired
    protected FilterChainProxy filterChainProxy;
    @Autowired
    protected WebApplicationContext context;
    protected static MockMvc mvc;

    @Before
    @Override
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        mvc = MockMvcBuilders.webAppContextSetup(context)
                .dispatchOptions(true)
                .addFilters(filterChainProxy)
                .build();
        authService = Mockito.mock(AuthService.class);
        Mockito.reset(authService);

        when(authService.getCurrentUser()).then(i->(getCurrentUser()));            
        when(authService.checkAuthority(any(UserAuthority.class))).
                                        thenReturn(true);

        login(WORKFLOW_USER);
    }

感谢任何帮助。提前谢谢!

1 个答案:

答案 0 :(得分:1)

只需删除此作业即可解决您的具体问题:

authService = Mockito.mock(AuthService.class);

您的目标是使用SpringJUnit4ClassRunner在图表中创建一些依赖项,并使用Mockito来模拟其他依赖项。但是,与this SO answer中一样,测试中标有@Autowired的任何内容都是在@Before方法运行之前创建的。这意味着您上面替换authService的调用只会覆盖测试中的字段;它不会调整或更改已创建的任何其他@Autowired字段,以及已使用您在Spring配置中绑定的authService的字段。

单元测试

如果这是一个单元测试,并且您只是测试TagsServiceTagsRepository,则可能需要通过使用@Mock和@Autowired字段的组合调用其构造函数来手动创建这些对象:

TagRepository repository = new TagRepository(/*mock*/ authService);
TagService tagService = new TagService(/*mock*/ authService, /*real*/ repository);

(Mockito提供了一种使用@InjectMocks自动创建模拟的方法,但是因为如果无法检测到适当的模拟,它会无声地失败,您可能希望避免这种情况并改为调用构造函数。{{ 3}})

请注意,上述内容仅适用于您在单元测试中直接使用对象,而不是当您依靠Spring的自动装配将对象更深入地插入图形时。

集成测试

您发布的测试看起来像是网络或集成测试,因此您希望在创建期间用模拟替换authService的实例。通常,这意味着要更改配置XML或ApplicationRunner,以指示Spring使用Mockito模拟而不是真正的AuthService。虽然有很多方法可以做到这一点,但您可能希望使用以Mockito为中心的FactoryBean See this article for some good reasons and solutions.

但等等!您可能正在使用已为Mockito定制的ApplicationRunner。由于三个原因,authService = Mockito.mock(AuthService.class);行看起来非常不合适:

  1. 你正在覆盖一个很少有意义的@Autowired字段
  2. 尽管存在Mockito.mock,但仍然是手动调用MockitoAnnotations.initMocks(this),这通常是首选
  3. 您立即reset您创建的模拟
  4. 这表明我的@Autowired authService 已经已经成为模拟者,并且已经已经有了存根,这就是为什么你有剩下的reset。如果是这样,那么你的问题不是关于Mockito的问题,除了你(或某人)已经覆盖字段并存根本地副本而不是Spring在整个网络测试中安装的副本。这可以很容易地解决:删除你的现场重新分配,你可能会很高兴。