如何在 Spring Boot 应用程序中为带有 @Configuration 注释的类编写单元测试用例
Posted
技术标签:
【中文标题】如何在 Spring Boot 应用程序中为带有 @Configuration 注释的类编写单元测试用例【英文标题】:How to write the unit test case for the Classes which are annotated with @Configuration in Spring Boot application 【发布时间】:2020-05-26 19:08:47 【问题描述】:我有一个配置类,它为RedissonClient
创建bean 并创建CacheManager
。如何为此配置类创建单元测试用例。
-
我们可以为
@Configuration
Class 编写单元测试用例吗?
如果可以,我们需要如何发展。
我更喜欢用 Groovy 在 Spock Framework 中编写测试用例。如果没有,请使用 Junit 或 Mockito 框架。如何为Spring Boot应用中@Configuration
注解的类编写单元测试用例
@Configuration
public class CacheConfiguration
private static final String CONFIG= "Configuration";
@Value("$redis.server.url")
private String redisUrl;
@Value("$redis.server.password")
private String password;
@Bean
public RedissonClient redissonClient()
Config config = new Config();
config.useSingleServer().setAddress(redisUrl).setPassword(password);
RedissonClient client = Redisson.create(config);
return client;
@Bean
public CacheManager redissonCacheManager(RedissonClient redissonClient)
Map<String, CacheConfig> config = new HashMap<String, CacheConfig>();
config.put(CONFIG, new CacheConfig(24*60*1000, 12*60*1000));
return new RedissonSpringCacheManager(redissonClient, config);
【问题讨论】:
单独测试它们没有真正意义,因为它们只在 Spring 应用程序中有意义。 是的。我同意,假设我们使用其他逻辑构建应用程序,那么我们需要如何确保覆盖使用 @Configuration 注释的类。 您可以像任何其他类一样对它进行单元测试,即通过调用其公共方法并验证结果,例如redissonClient()
实际上返回具有预期配置的 RedissonClient
实例。如果你想测试例如私有成员的值,这将是一个您也可以轻松编写的集成测试。但是问问自己,你是否真的想测试你的应用程序或者 Spring 容器是否有效。
@kriegaex 你能检查我的答案,并建议我的答案
@m-deinum :你能检查我的答案,并建议我的答案 -
【参考方案1】:
我认为你应该意识到带有@Configuration
注释的类并不是真正的java 类,或者至少你不应该这样对待它们。我知道这听起来有争议,我会解释...
所以历史上 Spring 使用 XML 配置来声明 bean。
我猜在 spring 2.5 中,他们引入了一种基于注解的方法,您将注解 @Component
/@Service
放在类上,将 @Autowired
放在您希望 spring 注入依赖项的任何位置,然后 spring 启动,扫描类路径,检测 bean 并使用这些 bean 启动应用程序上下文。
然后 Spring 3.0 引入了一种 Java Configuration 方式来做 spring 相关的配置:@Configuration / @Bean
在一个特殊的类中。
因此,您应该将这些配置类视为对我之前描述的方法的“替代”
现在让我问一下,你认为你应该自己测试和配置 XML bean 吗?可能不是...
您是否认为应该测试该类上是否有注释 @Component
并且所有必要的依赖项都是自动装配的(使用反射或其他方式)?应该不会吧。
那么为什么要测试 Java Config 类呢?
这是另一个你可能会觉得有趣的论点
我说过这些类仅用于 spring 来解析 bean 并在内部运行它们。但是 spring 不只是“运行”它们——它为它们创建了运行时包装器来克服一些技术问题。这是一个这样的例子:
以免假设我们有三个 bean:A、B、C,例如 B 和 C 依赖于 A。
class A
class B
private A a;
public B(A a) this.a = a;
class C
private A a;
public C(A a) this.a = a;
所有的bean都应该是单例的,所以我们这样定义配置:
@Configuration
public class MyConfig
@Bean
public A a() return new A();
@Bean
public B b() return new B(a());
public C c() return new C(a());
请注意,我们在 B
和 C
的定义中调用 a()
现在,让我问你一个问题:如果它是一个“常规”Java 代码,那么两个不同的方法 a()
(在 B 和 C 的构造函数中)调用应该如何分别返回 @ 的 相同实例 987654334@?
所以 spring 确实使用了很多复杂的代码,这是在运行时实际运行的代码,不是你的类,而是它的转换版本,你永远不知道这些转换到底是什么它和内部弹簧的东西。但是,测试它的意义何在?
我相信还有更多这样的论点,但重点很清楚——不要自己测试配置类。
相反,您可以使用集成测试来运行 spring 容器并加载配置中所需的所有类。但是,在这种情况下,您可能想要模拟一些类(例如使用 @MockBean
),因此它不会是 100% 准确的测试。
就代码覆盖率而言 - IMO 您应该将这些类完全排除在覆盖范围之外
【讨论】:
:感谢您提供的信息,这些信息非常有用。但是我确实看到有些人开发了 Groovy 测试用例,他们在其中启动了 spring 应用程序。就像你说的将运行弹簧容器的集成测试,如果我必须为上述配置做他们我必须做的事情。我对此完全陌生。 Spock 是一个基于 junit4 的 junit。因此,您可以将其与 Spring Boot 测试集成,如下所示:baeldung.com/spring-spock-testing 你能检查我的答案,并建议我的答案。【参考方案2】:经过一番研究发现,我们可以运行嵌入式redis服务器,我们可以通过启动应用程序来检查我们是否能够连接到redis服务器。我不知道这是否正确。但是这样做确实需要时间来完成它,大约需要 20 秒。使用以下依赖项来测试 //https://mvnrepository.com/artifact/it.ozimov/embedded-redis testCompile 组:'it.ozimov',名称:'embedded-redis',版本:'0.7.2'
@SpringBootTest(classes = [TestApp])
class CacheConfigurationSpec extends Specification
@Shared
RedisServer redisServer;
def setupSpec()
redisServer = RedisServer.builder()
.port(6379)
.setting("bind 127.0.0.1")
.setting("maxmemory 128M")
.build()
redisServer.start()
def cleanupSpec()
if (redisServer != null)
redisServer.stop()
@Autowired
private RedissonClient redissonClient;
def "load all contexts"()
@SpringBootApplication
class TestApp
static void main(String[] args)
SpringApplication.run(TestApp.class, args)
【讨论】:
如果你这样做,你实际上不需要在@SpringBootTest
中指定classes=[TestApp]
- 指定一个带有注册bean 的配置,它只会加载那个配置,并且测试会运行得更快。否则,它会尝试模仿整个应用程序的启动。总而言之,这是一个非常复杂的主题,有很多设施。如果你想真正了解它是如何工作的,我可以推荐这个会话:youtube.com/watch?v=Wpz6b8ZEgcU 另外请注意,该配置可以是可缓存的,因此如果你有很多测试类,spring 可以缓存应用程序。上下文并大大减少时间以上是关于如何在 Spring Boot 应用程序中为带有 @Configuration 注释的类编写单元测试用例的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Spring Boot / Spring Data 中为 Amazon RDS Mysql 启用 SSL?
我应该如何在 Gradle 中为 Spring Boot 应用程序设置主类?
如何在 Spring Boot 中为 Spring LDAP 身份验证设置覆盖 BindAuthenticator handleBindException
如何从 facebook/google/... oauth2 身份验证在 Spring (Boot) 中为单页应用程序派生自定义登录令牌?