如何为Spring Boot应用程序中用@Configuration注释的类编写单元测试用例
我有一个配置类,它为如何为Spring Boot应用程序中用@Configuration注释的类编写单元测试用例,spring,spring-boot,junit,spock,spring-boot-test,Spring,Spring Boot,Junit,Spock,Spring Boot Test,我有一个配置类,它为RedissonClient创建bean,还创建CacheManager。如何为此配置类创建单元测试用例 我们可以为@Configuration类编写单元测试用例吗 如果可以,我们需要如何发展 我更喜欢使用Groovy在Spock框架中编写测试用例。如果不是,则使用Junit或Mockito框架。如何为Spring Boot应用程序中用@Configuration注释的类编写单元测试用例 @Configuration public class CacheConfigurati
RedissonClient
创建bean,还创建CacheManager
。如何为此配置类创建单元测试用例
@Configuration
类编写单元测试用例吗@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);
}
}
@配置
公共类缓存配置{
私有静态最终字符串CONFIG=“Configuration”;
@值(${redis.server.url}”)
私有字符串地址;
@值(${redis.server.password}”)
私有字符串密码;
@豆子
公共RedissonClient RedissonClient(){
Config=new Config();
config.useSingleServer().setAddress(redisUrl).setPassword(password);
RedissonClient=Redisson.create(配置);
返回客户;
}
@豆子
公共缓存管理器redissonCacheManager(RedissonClient RedissonClient){
Map config=newhashmap();
config.put(config,新缓存配置(24*60*1000,12*60*1000));
返回新的RedissonSpringCacheManager(redissonClient,配置);
}
}
我认为您应该意识到用@Configuration
注释的类不是真正的java类,或者至少您不应该这样对待它们。我知道这听起来有争议,我会解释
所以历史上spring使用XML配置来声明bean
我想在Spring2.5中,他们引入了一种基于注释的方法,在类上放置注释@Component
/@Service
,将@Autowired
放置在希望spring注入依赖项的任何位置,然后spring启动,扫描类路径,检测bean并用这些bean启动应用程序上下文
然后,Spring3.0引入了一种Java配置方式来进行与Spring相关的配置:@Configuration/@Bean
在一个特殊的类中
因此,您应该将这些配置类视为我前面描述的方法的“替代”
现在让我问一下,您认为您应该单独测试XML和XMLBean配置吗?可能不是。。。
你认为你应该测试这个类是否有注释@组件
,并且所有必要的依赖项都是自动连接的(带有反射或其他什么)?可能不会
那么为什么要测试Java配置类呢?
这是另一个你可能会感兴趣的论点
我已经说过,这些类仅用于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的构造函数中)的两个不同调用如何分别返回a
的相同实例
所以spring确实使用了很多复杂的代码,这是运行时实际运行的代码,不是你的类,而是它的转换版本,你永远不知道这些转换到底是什么,因为它和内部spring的东西。但是这样做有什么意义呢?
我相信还有更多类似的争论,但问题很清楚——不要单独测试配置类
相反,您可以使用集成测试来运行spring容器并加载配置中所需的所有类。但是,在这种情况下,您可能希望模拟某些类(例如使用@MockBean
),因此它不是100%准确的测试
在代码覆盖率方面-IMO您应该将这些类完全排除在覆盖范围之外经过一些研究发现,我们可以运行嵌入式redis服务器,我们可以通过启动应用程序来检查是否能够连接到redis服务器。我不知道这是否正确。但这样做确实需要时间,大约需要20秒。使用以下依赖项来测试此//
testCompile组:“it.ozimov”,名称:“嵌入式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)
}
}
孤立地测试它们并没有真正意义,因为它们只在Spring应用程序中有意义。我同意,假设我们用其他逻辑构建了一个应用程序,那么我们需要如何确保使用@Configuration注释的类被覆盖。您可以像任何其他类一样对其进行单元测试,即调用其公共方法并验证结果,例如,redissonClient()
实际返回一个具有预期配置的RedissonClient
实例。如果您想测试私有成员的值,这将是一个集成测试,您也可以轻松编写。但是问问你自己,你是真的想测试你的应用程序还是Spring容器可以工作。@kriegaex你能检查我的答案,并提出我的建议吗answer@m-戴纳姆:你能检查一下我的答案,并建议我的答案吗?–:谢谢你提供的信息,非常有用。但我确实看到一些人开发了Groovy测试用例,他们在其中启动了spring应用程序。正如您所说的将运行spring容器的集成测试,如果我必须为上面的配置执行操作,那么它们将是我必须执行的操作。我对此一无所知。斯波克是在junit4的基础上构建的junit。因此,您可以将其集成到