【问题标题】:Java / Spring: Cannot test Caching in Unit TestJava / Spring:无法在单元测试中测试缓存
【发布时间】:2021-11-17 15:59:02
【问题描述】:

在我的 Java 应用程序中,我尝试使用单元测试来测试以下服务方法:

@Service
@EnableCaching
@RequiredArgsConstructor
public class LabelServiceImpl implements LabelService {

    private static final String CACHE_NAME = "demoCache";

    private final LabelRepository labelRepository;


    @Override
    public List<LabelDTO> findByUuid(UUID uuid) {
        final Label label = labelRepository.findByUuid(uuid)
                .orElseThrow(() -> new EntityNotFoundException("Not found."));
        final List<LabelDTO> labelList = labelRepository.findByUuid(uuid);
        return labelList;
    }
}

这是我的单元测试:

@Import({CacheConfig.class, LabelServiceImpl.class})
@ExtendWith(SpringExtension.class)
@EnableCaching
@ImportAutoConfiguration(classes = {
        CacheAutoConfiguration.class,
        RedisAutoConfiguration.class
})
@RunWith(MockitoJUnitRunner.class)
public class CachingTest {

    @InjectMocks
    private LabelServiceImpl labelService;

    @Autowired
    private CacheManager cacheManager;


    @Mock
    private LabelRepository labelRepository;


    @Test
    void givenRedisCaching_whenFindUuid_thenReturnFromCache() {

        //code omitted 
        
        LabelDTO labelFromDb = labelService.findByUuid(uuid);
        LabelDTO labelFromCache = labelService.findByUuid(uuid);
        verify(labelRepository, times(1)).findByUuid(uuid);
    }
}

当我在单元测试中将@Autowired 用于LabelServiceImpl 时,我收到“Nullpointer 异常”错误。如果我对该实例使用@InjectMocks 注释,则不会出现错误,但不会进行缓存(它调用labelService.findByUuid 2 次而不是1 次)。

我认为我犯了与单元测试类中的注释有关的错误,但我尝试了许多不同的组合并不能解决问题。

那么,我该如何解决这个问题?

更新:最后我使用以下方法解决了这个问题。但是,我还必须将mockito-core 版本从3.3.3 更新为3.7.0,如下所示。否则我会收到“java.lang.NoSuchMethodError: org.mockito.MockitoAnnotations.openMocks(Ljava/lang/Object;)Ljava/lang/Au​​toCloseable;”错误。

pom.xml:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>3.7.0</version>
    <scope>test</scope>
</dependency>

缓存测试:

@ExtendWith(MockitoExtension.class)
@SpringBootTest
public class CachingTest {

    @Autowired
    @InjectMocks
    private LabelServiceImpl labelService;
        
    @MockBean
    private LabelRepository labelRepository;

    @Test
    public void givenRedisCaching_whenFindUuid_thenReturnFromCache() {
        //code omitted 
        
        LabelDTO labelFromDb = labelService.findByUuid(uuid);
        LabelDTO labelFromCache = labelService.findByUuid(uuid);
        verify(labelRepository, times(1)).findByUuid(uuid);
        assertEquals(labelFromDb, labelFromCache);              
    }
}

【问题讨论】:

  • 请不要再问同样的问题,而是改写或澄清您就此提出的其他问题。正如我在另一篇文章中所说,您的测试没有意义,大多数注释都是无用的,您期望在没有向测试中添加弹簧功能的模拟模拟将测试弹簧功能。这当然不会发生。 Autowire LabelService 不是 impl,放弃所有注释,只需添加 @SpringBootTest 并将 @Mock 替换为 @MockBean。我记得对您的另一个问题(似乎已被删除)给出了相同的答案/评论。
  • 非常感谢。如果我使用 @SpringBootTest 注释,我会得到 labelService 的“java.lang.NullPointerException”(我也将其更改为接口 -> LabelService)。
  • 另一方面,如果我在 @SpringBootTest 之外添加 @RunWith(SpringRunner.class),那么我会得到 "java.lang.IllegalArgumentException: Cannot find cache named 'demoCache' for Builder[public java. util.List com.mycompany.service.impl.LabelServiceImpl.findByUuid(UUID)] caches=[demoCache] | key='' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | 除非='' | sync='false'" 错误。 但是我认为我们非常接近解决方案,因为它会查找缓存,但无法找到该名称。
  • 我也试过在我的测试类上添加@EnableCaching注解,但还是同样的问题。
  • 如果您使用的是 junit4(我假设为 5),您还需要 @RunWith。您需要配置缓存管理器以创建该缓存(显然您使用的缓存不支持即时创建)。

标签: java spring spring-boot unit-testing junit


【解决方案1】:

Mockito 不会模拟您的 springt 启动应用程序。它只是模拟带注释的对象并将您的模拟对象注入到您的 labelService 中。

另一方面,测试 Spring Boot 应用程序 @Autowired 是不够的。

您必须构建一个 Spring Boot 集成测试。 为此,请使用 @SpringBootTest 注释您的测试。 这会初始化一个真正的应用程序上下文。

尝试自动装配,LabelService

package com.demo;

import org.springframework.stereotype.Service;
@Service
public class LabelService
{
    public String getLabel()
    {
        return "Test Label " + System.currentTimeMillis();
    }
}

package com.demo;

import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class CachingTest
{
    @Autowired
    private LabelService labelService;

    @Test
    public void testLabelService()
    {
        assertNotNull(labelService);
    }
}

这行得通

【讨论】:

  • 谢谢安德烈亚斯,我也试过@SpringBootTest,但labelService 为空(我通过@Autowired 对其进行了注释。有任何想法吗?
  • 尝试自动装配,LabelService
  • 我在回答中添加了一个示例
  • 我的更新呢?它现在正在工作,我认为可以通过 Unit Test 以及集成测试来测试缓存。关于更新代码的任何评论?可以吗,或者你有什么相关的建议吗?
  • @Robert 请在link查看我的回答。
猜你喜欢
  • 2021-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-16
  • 2021-03-05
  • 1970-01-01
  • 2021-12-04
相关资源
最近更新 更多