- Environment: JDK13, IDEA, springboot2 5.3,maven3. eight point one
catalogue
1, Automatic configuration of data sources
Configure the Druid data source in custom mode
Configure Druid data source monitoring page function
Configure the Druid data source in the official starter mode [recommended]
2, Integrate Mybatis operations
1, Automatic configuration of data sources
1. Import jdbc scene
Import initiator
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jdbc</artifactId> </dependency>
In addition, you should import the database driver according to the database type you use. This article uses the MySQL 8 version database without selecting the version. springboot has version arbitration for this
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
Analysis auto configuration
1. Automatically configured classes
- DataSourceAutoConfiguration: automatic configuration of data sources
- Modify the configuration related to the data source: spring datasource
- The configuration of database connection pool is automatically configured only when there is no DataSource in its own container
- The bottom configured connection pool is HikariDataSource
@Configuration(proxyBeanMethods = false) @Conditional(PooledDataSourceCondition.class) @ConditionalOnMissingBean({ DataSource.class, XADataSource.class }) @Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class, DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.OracleUcp.class, DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class }) protected static class PooledDataSourceConfiguration
- DataSourceTransactionManagerAutoConfiguration: automatic configuration of the transaction manager
- JdbcTemplateAutoConfiguration: the automatic configuration of JdbcTemplate, which can be used to crud the database
- You can modify the configuration item @ ConfigurationProperties(prefix = "spring.jdbc") to modify the JdbcTemplate
- @ Bean@Primary JdbcTemplate; There is this component in the container
- JndiDataSourceAutoConfiguration: automatic configuration of jndi
- XADataSourceAutoConfiguration: distributed transaction related
Test:
@Slf4j @SpringBootTest class Boot05WebAdminApplicationTests { @Autowired JdbcTemplate jdbcTemplate; @Test void contextLoads() { // jdbcTemplate.queryForObject("select * from account_tbl") // jdbcTemplate.queryForList("select * from account_tbl",) Long aLong = jdbcTemplate.queryForObject("select count(*) from account_tbl", Long.class); log.info("Total records:{}",aLong); } }
2. Using Druid data sources
Configure the Druid data source in custom mode
1. Create a configuration file class and introduce application Configuration of database information in yaml file
@Configuration public class MyDataSource { /** * Configure Druid data sources * @return */ @ConfigurationProperties("spring.datasource") @Bean public DataSource dataSource() throws SQLException { DruidDataSource druidDataSource = new DruidDataSource(); //Turn on the monitoring function of the monitoring page druidDataSource.setFilters("stat"); return druidDataSource; } }
2. Testing
package com.young; import com.alibaba.druid.pool.DruidDataSource; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.jdbc.core.JdbcTemplate; import javax.sql.DataSource; @SpringBootTest @Slf4j class BootWeb05ApplicationTests { // @Autowired // JdbcTemplate jdbcTemplate; @Autowired DataSource dataSource; @Test void contextLoads() { log.info("The data source is====>"+dataSource.getClass()); } }
result
Configure Druid data source monitoring page function
Note: when using the monitoring page, if you want to use the monitoring function, you need to turn on the monitoring function when configuring the data source
/** * Configure monitoring page function * @return */ @Bean public ServletRegistrationBean<StatViewServlet> statViewServlet(){ StatViewServlet statViewServlet = new StatViewServlet(); return new ServletRegistrationBean<StatViewServlet>(statViewServlet,"/druid/*"); }
Configure the Druid data source in the official starter mode [recommended]
First introduce the starter
<!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.3</version>
</dependency>
Analysis auto configuration
- Extension configuration item spring datasource. druid
- DruidSpringAopConfiguration.class to monitor the of SpringBean; Configuration item: spring datasource. druid. aop-patterns
- DruidStatViewServletConfiguration.class, monitoring page configuration: spring datasource. druid. stat-view-servlet; Default on
- DruidWebStatFilterConfiguration.class, web monitoring configuration; spring.datasource.druid.web-stat-filter; Default on
- DruidFilterConfiguration.class}) configuration of all Druid filter s
private static final String FILTER_STAT_PREFIX = "spring.datasource.druid.filter.stat"; private static final String FILTER_CONFIG_PREFIX = "spring.datasource.druid.filter.config"; private static final String FILTER_ENCODING_PREFIX = "spring.datasource.druid.filter.encoding"; private static final String FILTER_SLF4J_PREFIX = "spring.datasource.druid.filter.slf4j"; private static final String FILTER_LOG4J_PREFIX = "spring.datasource.druid.filter.log4j"; private static final String FILTER_LOG4J2_PREFIX = "spring.datasource.druid.filter.log4j2"; private static final String FILTER_COMMONS_LOG_PREFIX = "spring.datasource.druid.filter.commons-log"; private static final String FILTER_WALL_PREFIX = "spring.datasource.druid.filter.wall";
Configuration example
spring: datasource: url: jdbc:mysql://localhost:3306/db_account username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver druid: aop-patterns: com.atguigu.admin.* #Monitoring springbeans filters: stat,wall # Bottom open function, stat (sql monitoring), wall (firewall) stat-view-servlet: # Configure monitoring page function enabled: true login-username: admin login-password: admin resetEnable: false web-stat-filter: # Monitoring web enabled: true urlPattern: /* exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*' filter: stat: # Detailed configuration of stat in the above filters slow-sql-millis: 1000 logSlowSql: true enabled: true wall: enabled: true config: drop-table-allow: false
2, Integrate Mybatis operations
Export dependency
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency>
1. Configuration mode
- Global profile
- SqlSessionFactory: Auto configured
- SqlSession: SqlSessionTemplate is automatically configured and SqlSession is combined
- @Import(AutoConfiguredMapperScannerRegistrar.class);
- Mapper: as long as the interface of MyBatis is marked with @ mapper, it will be automatically scanned
@EnableConfigurationProperties(MybatisProperties.class) : MyBatis Configuration item binding class. @AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class }) public class MybatisAutoConfiguration{} @ConfigurationProperties(prefix = "mybatis") public class MybatisProperties
You can modify all the settings in the configuration file that start with mybatis;
# Configure mybatis rules mybatis: config-location: classpath:mybatis/mybatis-config.xml #Global profile location mapper-locations: classpath:mybatis/mapper/*.xml #sql mapping file location
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.young.mapper.StudentMapper"> <select id="queryUsers" resultType="student"> select * from student </select> </mapper>
Instead of using the mybatis configuration file, you can configure it all in the yaml file
mybatis: # config-location: classpath:mybatis/mybatis-config.xml #Global profile location mapper-locations: classpath:mybatis/mapper/*.xml #sql mapping file location configuration: map-underscore-to-camel-case: true #Map underscores to hump naming type-aliases-package: com.young #Yes, com Open the alias of the class under the young package
This method needs to disable the location of the global configuration file
2. Mixed mode
@Mapper public interface CityMapper { @Select("select * from city where id=#{id}") public City getById(Long id); public void insert(City city); }
Best practice:
- Introducing mybatis starter
- Configure application In yaml, specify the mapper location
- Write Mapper interface and annotate @ Mapper annotation
- Simple method direct annotation method
- Write mapper with complex method XML binding mapping
- @MapperScan("com.atguigu.admin.mapper") is simplified, and other interfaces do not need to be annotated with @ mapper annotation
3, Junit5
1. JUnit 5 changes
Spring boot version 2.2.0 began to introduce JUnit 5 as the default library for unit testing
As the latest version of JUnit framework, JUnit 5 is very different from the previous version of JUnit framework. It consists of several different modules of three different subprojects.
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
JUnit Platform: Junit Platform is the basis for starting the test framework on the JVM. It supports not only Junit's self-made test engine, but also other test engines.
JUnit Jupiter: JUnit Jupiter provides a new programming model of JUnit 5 and is the core of JUnit 5's new features. A test engine is included internally to run on the Junit Platform.
JUnit Vintage: since JUint has developed for many years, in order to take care of old projects, JUnit Vintage provides JUnit 4.0 compatible services x,Junit3. X test engine.
be careful:
Springboot versions above 2.4 remove the default dependency on Vintage. If you need to be compatible with junit4, you need to introduce it yourself (you can't use the function @ Test of junit4)
JUnit 5's vintage engine removed from spring boot starter test. If you need to continue to be compatible with junit4, you need to introduce vintage by yourself
<dependency> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-core</artifactId> </exclusion> </exclusions> </dependency>
2. Common notes
junit user manual https://junit.org/junit5/docs/current/user-guide/
- @Test: indicates that the method is a test method. However, unlike JUnit4's @ test, it has a very single responsibility and cannot declare any attributes. Jupiter will provide additional tests for expanded tests
- @ParameterizedTest: indicates that the method is parameterized test, which will be described in detail below
- @RepeatedTest: indicates that the method can be executed repeatedly, which will be described in detail below
@DisplayName("test@RepeatedTest") @RepeatedTest(5) @Test public void RepeatedTest(){ System.out.println("666"); }
- @DisplayName: set the display name for the test class or test method
-
@DisplayName("junit5 Functional test class") public class Junit5Test { @DisplayName("test@DisplayName annotation") @Test public void testDisplayName(){ System.out.println("1"); } }
-
@Before each: indicates to execute before each unit test
@BeforeEach void beforeEach(){ System.out.println("beforeEach It's running..."); }
- @After each: means to execute after each unit test
Use the same method as @ BeforeEach
- @Before all: indicates to execute before all unit tests
- @After all: means to execute after all unit tests
Integration test for @ BeforeEach @AfterEach @BeforeAll @AfterAll
package com.young; import org.junit.jupiter.api.*; @DisplayName("junit5 Functional test class") public class Junit5Test { @DisplayName("test@DisplayName Note 1") @Test public void testDisplayName(){ System.out.println("1"); } @DisplayName("test@DisplayName Note 2") @Test public void testDisplayName1(){ System.out.println("2"); } @BeforeEach void beforeEach(){ System.out.println("beforeEach It's running..."); } @AfterEach void afterEach(){ System.out.println("afterEach It's running..."); } @BeforeAll static void beforeAll(){ System.out.println("All methods are about to start running..."); } @AfterAll static void AfterAll(){ System.out.println("All the methods are over..."); } }
- @Tag: indicates the unit test category, similar to @ Categories in JUnit4
- @Disabled: indicates that the test class or test method is not executed, similar to @ Ignore in JUnit 4
- @Timeout: indicates that the test method will return an error if it exceeds the specified time
- @ExtendWith: provides an extension class reference for a test class or test method
- @SpringBootTest: after marking on the test class, the test class can use the Spring container function
import org.junit.jupiter.api.Test; //Note that the Test annotation of jupiter is used here!!
3. assertions
Assertions are the core part of the test method, which is used to verify the conditions that the test needs to meet. These assertion methods are org junit. jupiter. api. Static method for assertions. The built-in assertions in JUnit 5 can be divided into the following categories:
Check whether the data returned by the business logic is reasonable.
After all test runs are completed, there will be a detailed test report;
① Simple assertion
Used for simple validation of a single value. For example:
method | explain |
assertEquals | Determines whether two objects or two primitive types are equal |
assertNotEquals | Determines whether two objects or two primitive types are not equal |
assertSame | Judge whether two object references point to the same object |
assertNotSame | Judge whether two object references point to different objects |
assertTrue | Determines whether the given Boolean value is true |
assertFalse | Determines whether the given Boolean value is false |
assertNull | Determines whether the given object reference is null |
assertNotNull | Determines whether the given object reference is not null |
Test simply as follows:
@Test @DisplayName("Test simple assertions") public void testAssert(){ int cal = cal(2, 3); assertEquals(6,cal,"The calculation is wrong..."); } int cal(int i,int j){ return i + j; }
②. Array assertion
Use the assertArrayEquals method to determine whether two objects or arrays of the original type are equal
@Test @DisplayName("array assertion") public void array() { assertArrayEquals(new int[]{1, 2}, new int[] {1, 2}); }
③ Combination assertion
The assertAll method accepts multiple org junit. jupiter. api. As the assertions to be verified, the instance of the executable functional interface can easily provide these assertions through lambda expressions
@Test @DisplayName("assert all") public void all() { assertAll("Math", () -> assertEquals(2, 1 + 1), () -> assertTrue(1 > 0) ); }
④ . exception assertion
In JUnit 4, when you want to test the exception of a method, the ExpectedException variable annotated with @ Rule is still troublesome. JUnit 5 provides a new assertion method, assertions Assertthrows() can be used in conjunction with functional programming.
@Test @DisplayName("Abnormal test") public void exceptionTest() { ArithmeticException exception = Assertions.assertThrows( //Throw assertion exception ArithmeticException.class, () -> System.out.println(1 % 0)); }
⑤ . timeout assertion
Junit5 also provides assertions Asserttimeout() sets a timeout for the test method
@Test @DisplayName("Timeout tests ") public void timeoutTest() { //If the test method takes more than 1s, it will be abnormal Assertions.assertTimeout(Duration.ofMillis(1000), () -> Thread.sleep(500)); }
⑥ . quick failure
Make the test fail directly through the fail method
@Test @DisplayName("fail") public void shouldFail() { fail("This should fail"); }
4. Preconditions
Preconditions in JUnit 5 are similar to assertions. The difference is that unsatisfied assertions will fail the test method, while unsatisfied preconditions will only terminate the execution of the test method. Preconditions can be regarded as the premise of test method execution. When the premise is not met, there is no need to continue execution.
@DisplayName("Preconditions") public class AssumptionsTest { private final String environment = "DEV"; @Test @DisplayName("simple") public void simpleAssume() { assumeTrue(Objects.equals(this.environment, "DEV")); assumeFalse(() -> Objects.equals(this.environment, "PROD")); } @Test @DisplayName("assume then do") public void assumeThenDo() { assumingThat( Objects.equals(this.environment, "DEV"), () -> System.out.println("In DEV") ); } }
assumeTrue and assumFalse ensure that the given condition is true or false. If the condition is not met, the test execution will be terminated. The parameter assemingthat is the Boolean value representing the condition and the implementation object of the corresponding Executable interface. The Executable object will be executed only when the conditions are met; When the conditions are not met, the test execution does not terminate.
5. Nested test
JUnit 5 can implement Nested tests through internal classes and @ Nested annotations in Java, so as to better organize relevant test methods together. You can use @ BeforeEach and @ AfterEach annotations in internal classes, and there is no limit to the nesting level.
@DisplayName("A stack") class TestingAStackDemo { Stack<Object> stack; @Test @DisplayName("is instantiated with new Stack()") void isInstantiatedWithNew() { new Stack<>(); } @Nested @DisplayName("when new") class WhenNew { @BeforeEach void createNewStack() { stack = new Stack<>(); } @Test @DisplayName("is empty") void isEmpty() { assertTrue(stack.isEmpty()); } @Test @DisplayName("throws EmptyStackException when popped") void throwsExceptionWhenPopped() { assertThrows(EmptyStackException.class, stack::pop); } @Test @DisplayName("throws EmptyStackException when peeked") void throwsExceptionWhenPeeked() { assertThrows(EmptyStackException.class, stack::peek); } @Nested @DisplayName("after pushing an element") class AfterPushing { String anElement = "an element"; @BeforeEach void pushAnElement() { stack.push(anElement); } @Test @DisplayName("it is no longer empty") void isNotEmpty() { assertFalse(stack.isEmpty()); } @Test @DisplayName("returns the element when popped and is empty") void returnElementWhenPopped() { assertEquals(anElement, stack.pop()); assertTrue(stack.isEmpty()); } @Test @DisplayName("returns the element when peeked but remains not empty") void returnElementWhenPeeked() { assertEquals(anElement, stack.peek()); assertFalse(stack.isEmpty()); } } } }
6. Parametric test
Parametric testing is a very important new feature of JUnit 5. It makes it possible to run tests multiple times with different parameters, and also brings a lot of convenience to our unit testing.
Using @ ValueSource and other annotations to specify input parameters, we can use different parameters for multiple unit tests without adding a unit test every time a parameter is added, saving a lot of redundant code.
@ValueSource: Specifies the input parameter source for parametric testing. It supports eight basic classes, String type and Class type
@NullSource: indicates that a null input parameter is provided for the parameterized test
@EnumSource: indicates that an enumeration input parameter is provided for the parameterized test
@CsvFileSource: read the contents of the specified CSV file as the parametric test input parameter
@MethodSource: means to read the return value of the specified method as the parameterized test input parameter (note that the method return needs to be a stream)
Of course, if the parametric test can only specify ordinary input parameters, it can not reach the point that makes me feel amazing. What makes me really feel his strength is that he can support all kinds of external participation. For example, CSV,YML,JSON files and even the return value of methods can also be used as input parameters. You only need to implement the ArgumentsProvider interface, and any external file can be used as its input parameter.
@ParameterizedTest @ValueSource(strings = {"one", "two", "three"}) @DisplayName("Parametric test 1") public void parameterizedTest1(String string) { System.out.println(string); Assertions.assertTrue(StringUtils.isNotBlank(string)); } @ParameterizedTest @MethodSource("method") //Specify method name @DisplayName("Method source parameters") public void testWithExplicitLocalMethodSource(String name) { System.out.println(name); Assertions.assertNotNull(name); } static Stream<String> method() { return Stream.of("apple", "banana"); }