Test related springboot Junit for java projects

When I was writing code before, due to time constraints and other reasons, I always felt that writing unit tests was an extra workload, and I didn’t like to write or make up after the development was completed. Really meaningful. But this often leads to other problems after modifying one problem without knowing it.

So unit testing is still necessary. Then I researched recently, what method and tool should be used to test, and I also found a lot of information on the Internet, basically all of them are spock (written in groovy, haven't used it yet, try it later), and said that Learn from the test idea of ​​appfuse (Baidu by yourself), what DBUnit, JUnit and so on.

These are just a little understanding of myself, but I also know how to use some of them. In view of my own needs, I finally chose JUnit, mockMvc, h2 database

 

Own system situation:

A web project implemented using Springboot + mybatis + mySql

 

The general idea is to unit test all three layers

1. dao

2、service

3、controller

 

1. dao

SpringBoot integrates H2 test Dao to view this log: http://blog.csdn.net/mn960mn/article/details/54644908

https://segmentfault.com/a/1190000007002140

 

Because when the initial table data in the h2 configuration, if you directly use INIT=RUNSCRIPT FROM to import and insert data, but I don't know why the data is inserted 10 times, so there is no way but to change the way, use spring. datasource.data is initialized.

 

## 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 

Testing the service is also relatively simple, you only need to execute the scan package of the service. In this way, the corresponding bean can be used in the test class.

 

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

}
 

 

 3、controller

This is a place where there are many problems during testing. In fact, it would be fine if a normal mysql database (the one used for normal development) was used, but in order to separate the database for unit testing and development, this H2 was added. There is a problem with the database.

The reason is that we redefine the datasource ourselves 

 

@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();
    }
}

 

  Note: The above code has some logic of its own, so it should not be easy to modify the configuration directly to h2, because it is the added Test, so the original code will not be touched

 

Normally in the Test file, specifying @SpringBootTest(classes={Application.class}) can load and initialize all the required content, but since the datasource is configured in the form of @bean, the configuration in the configuration file will be loaded when loading. The default datasource is overridden, and the configuration information at the beginning of my.jdbc is used. There is no way to use the H2 database.

 

Then I thought of using @SpringBootTest(classes={Application.class}) directly. Instead, only introduce what you need, just like the Dao test, and then create a

 

@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地址了。

 

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

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326392530&siteId=291194637