java项目的测试相关 springboot Junit

之前的编写代码的时候,由于时间限制等原因,一直觉得写单元测试是额外的工作量,也不爱写或者是开发完成之后再后补,有应付了事的嫌疑,没有做出单元测试的真是意义。但是这样往往会在修改完一个问题之后,可能引起其他问题而不自知。

所以单元测试还是有必要的。然后最近就研究了一下,应该用何种方式,什么工具去做测试,网上也找了一堆资料,基本上都是spock(groovy编写,还未使用过,后续试试),还有说要借鉴appfuse的测试思想去做(自行百度吧),什么DBUnit ,JUnit等等吧。

这些只是自己初略了解了下,但是具体有些也清楚怎么用,鉴于自己的需求,最后选择了JUnit,mockMvc,h2 database

 

自身系统情况:

使用Springboot + mybatis + mySql 实现的web项目

 

大致的思路是把三层都可以进行单元测试

1、dao

2、service

3、controller

 

1、dao

SpringBoot 整合H2测试Dao可以查看这篇日志: http://blog.csdn.net/mn960mn/article/details/54644908

https://segmentfault.com/a/1190000007002140

因为 h2的配置中初始话表数据的时候,如果直接是使用INIT=RUNSCRIPT FROM 这种引入插入数据的时候,但是不知道为什么 数据被插入了10遍,所以没办法只能更换方式,使用spring.datasource.data 进行初始化了。

## h2 database
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:test;MODE=MYSQL;
##INIT=RUNSCRIPT FROM 'classpath:sql/init_table.sql'\\;RUNSCRIPT FROM 'classpath:sql/init_data.sql'  ## this i don't konw why it insert 10 datas
#spring.datasource.url=jdbc:h2:file:~/.h2/db_users;MODE=MYSQL;AUTO_SERVER=TRUE;   ## file save to local
spring.datasource.username=
spring.datasource.password=
spring.datasource.schema=classpath:sql/init_table.sql
spring.datasource.data=classpath:sql/init_data.sql
 

2、service 

测试service也比较简单,只需要执行service的扫描包就可以了。这样在测试类中就可以使用相应的bean了。

@Configuration
@ComponentScan(basePackages = {"com.test.service.**"})
public class ServiceConfiguration {

}
 

 3、controller

这个是在测试的时候问题比较多的地方,其实原本如果使用的是正常的mysql数据库(跟平时开发用的一个)也还好,但是为了实现单体测试和开发那个数据库分离,添加的这个H2数据库就出现问题了。

原因是我们自己重新定义了datasource 

 

@Configuration
@MapperScan({ "com.xxx.**.mapper"})
@ComponentScan({ "com.xxx.datasource"})
@Slf4j
public class MapperAdminConfiguration {
    @Bean
    @ConfigurationProperties(prefix="my.jdbc")
    public MyDataSource dataSource() {
       return (MyDataSource ) DataSourceBuilder.create()
                                                    .type(MyDataSource.class).build();
    }
} 

  注意:  以上代码有一些自身的逻辑,所以直接修改配置变为h2应该是不好用的,因为是后加的Test,所以不会动原来的代码

 

正常在Test文件中,指定 @SpringBootTest(classes={Application.class})就可以把需要的内容都进行加载初始化,但是由于通过@bean形式配置了datasource,那么加载时就会把配置文件中配置的默认的datasource进行覆盖,而去使用my.jdbc开头的配置信息。就没办法使用H2数据库了.

 

那么就想到了直接使用@SpringBootTest(classes={Application.class})这个。而是只引入自己需要的,就像Dao测试那样,然后自己就建立了一个

 

@Configuration
@ComponentScan(basePackages = {"com.xxxx.**")
public class ServiceConfiguration {

}
 

 

@RunWith(SpringRunner.class)  
/** 
 *  这里指定的classes是可选的。如果不指定classes,则spring boot会启动整个spring容器,很慢(比如说会执行一些初始化,ApplicationRunner、CommandLineRunner等等)。不推荐 
 *  指定的话,就只会初始化指定的bean,速度快,推荐 
 */  
@SpringBootTest(classes={DataSourceAutoConfiguration.class, MybatisAutoConfiguration.class, 
        MapperConfiguration.class,ServiceConfiguration.class})
@WebAppConfiguration
public class PlatformControllerTest {  
    
    MockMvc mvc;  
    
    @Autowired  
    WebApplicationContext webApplicationContext;  
    
    @Before  
    public void setUp() {  
        mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();  
    }  
     
    @Test  
    public void list() throws Exception {  
        String uri = "/admin/admin/platform/list/all";  
        MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.get(uri).accept(MediaType.APPLICATION_JSON)).andReturn();  
        int status = mvcResult.getResponse().getStatus();  
        String result = mvcResult.getResponse().getContentAsString();  
        Assert.assertTrue("Wrong,status not 200 ,is " + status, status == 200);  
        Assert.assertFalse("Wrong,status not 200 ,is " + status, status != 200);  
    }  
    
    
    
    //@Test   
    public void testList(){
        RestTemplate restTemplate = new RestTemplate();//测试http请求的
        String url = "http://localhost:8080/admin/admin/platform/list/all";
        Map map = new HashMap<>();
        String result = restTemplate.getForObject(url, String.class, map);
        System.out.print(result+"=========");
    }
    
}  
 

但是问题出现了,因为返回的是对象,在list()方法返回的http状态一直是406,原因应该是在messageConverter的时候没有转,正常情况下SpringBoot是有一个WebMvcAutoConfiguration ,里边会添加上一些默认的HttpMessageConverters,自动进行转换的,但是现在不好用了,说明这个没有进行加载。

 

为什么使用 @SpringBootTest(classes={Application.class}) 可以加载进来,具体是怎么加载我也看不明白,无奈只能先看看Application类都有哪些东西吧

 

 

@SpringBootApplication
@EnableAspectJAutoProxy
public class Application {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }

}
 
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {....}
 

   发现一个这样的注解 @EnableAutoConfiguration  

 相关解释: http://www.logicbig.com/tutorials/spring-framework/spring-boot/enable-auto-config/

 

Using @EnableAutoConfiguration is like using @Configuration annotation. It configures and wires our beans based on what @Bean methods we have defined in our configuration class. It does other additional configurations too, which includes configuring/invoking helper components (like embedded tomcat in web application). This mechanism works based on the jar dependencies available in the classpath. The jar are usually supplied via starter dependencies, but that's not the absolute requirement. The two things (starters and auto-configuration) are not dependent on each others.

使用@EnableAutoConfiguration就像使用@Configuration注释一样。 它根据我们在配置类中定义的@Bean方法来配置和连接我们的bean。 它还执行其他附加配置,其中包括配置/调用辅助组件(如Web应用程序中的嵌入式tomcat)。 此机制基于类路径中可用的jar依赖项起作用。 这个jar通常是通过启动器依赖来提供的,但这不是绝对的要求。 这两件事(启动器和自动配置)不依赖于彼此。

把这个标签加上之后,Ok了,可以进行messageConverter了。

那么现在就可以进行两个数据源的切换了,如果想使用开发时的mySql进行测试,可以直接在Test类中@SpringBootTest(classes={Application.class})就可以了,就可以初始化@bean定义的datasource,

如果想使用H2进行测试,那么就可以分别引入classes

@SpringBootTest(classes={DataSourceAutoConfiguration.class, MybatisAutoConfiguration.class, 
        MapperConfiguration.class,ServiceConfiguration.class})

 

springBoot就会去读取配置文件中的H2地址了。

 

出现问题的原因根本还是在于对于框架的本质原理不懂,只能看到表象的内容,其实最后就是一个注解引起的问题。

 

猜你喜欢

转载自slnddd.iteye.com/blog/2383615
今日推荐