Summary of unit test and project quality management, unit test quality management
Abstract: If no unit test is written, if the previous code is reconstructed in branch, there is no courage to move back to trunck. With the unit test, you are confident to merge after all the tests pass. Internet companies need to pay more attention to unit tests because version iterations are fast. Therefore, a good unit test framework and a good project quality management are very important. This article is my experience on these issues. Key words: java, unit test, TestNG, DbUnit, Spring, project management, quality management, PMP solution problem: how should we implement unit test? How to Implement project quality management?
When developing the Data Access Object DAO layer, We need to directly add, delete, modify, and query CRUD operations on the data layer. Unit Testing is very important, because code refactoring is often required during development. How can we ensure the correctness of code refactoring? How can we give the code reconfigurator confidence to let him do it, to perform unit tests, developers can do this boldly as long as they can ensure that the interface functions do not change, they are exactly the same as before code refactoring, and can intuitively feel this consistency. Easy function development and hard unit testing. First, the interaction between unit tests: A new piece of data added to unit test 1 may affect the correctness of unit test 2 verification, you may think of manual initialization at the beginning of each unit test, such as clearing the data in the table to clear the impact of other unit tests. This is stupid and increases the workload. Second, developers interact with each other: if multiple developers need to execute test cases at the same time, problems still occur after using the above methods, at this time, we may choose each developer to build a set of databases (memory or large) on their own to avoid interference from many people. This is too troublesome and consumes resources. The following is a unit test framework based on TestNG and DbUnit. Its basic idea is to manage transactions, use transactions at the beginning of unit test, and roll back the transactions at the end of the unit test logic, therefore, database operations in each unit test will not actually have a substantial impact on the database. In this way, the logic correctness can be tested in unit test, it also avoids affecting other unit tests and other developers, and relies only on the Unified Development Database, which is convenient to use. The following uses the MyBatis function to abstract a unified platform that provides most public interfaces, such as adding, deleting, modifying, querying, and batch operations, most basic operations can be completed by calling these interfaces, and SQL statements can be passed in for non-General operations.
1. MyBatis unified platform: MyBatisAngelWang. class
@RepositorypublicclassMyBatisAngelWangimplementsIRepository{@AutowiredprivateGeneralDAO generalDAO;public<T extendsBase> T get(Class<T> clz,Long id){HashMap hashMap = generalDAO.getLogically(clz, id);T ret =this.convert(hashMap, clz);return ret;}}
The above Code directly operates the database. We need to write a unit test for this interface. The specific usage of MyBatis and the implementation of the MyBatisAngelWang unified platform need to be discussed in detail in a special chapter. I will not conduct further research here.
Ii. Unit Test of the unified platform: MyBatisAngelWangTest
import org.testng.annotations.Test;//@DatabaseSetup(value= "/dbunitData/TestAngelEntity.xml")publicclassMyBatisAngelWangTestextendsAbstractRollbackTest{@AutowiredprivateMyBatisAngelWang myBatisAngelWang;@Test(enabled =false)publicvoid testGet(){}}
The unit test MyBatisAngelWangTest. class inherits from an abstract class: AbstractRollbackTest.
import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.TestExecutionListeners;@ContextConfiguration(locations ={"classpath:spring-datasource-dbunit.xml","classpath*:spring-services.xml"})@TestExecutionListeners({DependencyInjectionTestExecutionListener.class,TransactionDbUnitTestExecutionListener.class,TransactionalTestExecutionListener.class})@TransactionalpublicclassAbstractRollbackTestextendsAbstractTestNGSpringContextTests{}
This abstract class is defined by ourselves and inherited from the abstract class: AbstractTestNGSpringContextTests, which is provided by Springframework. We can inject the spring configuration file through the ContextConfiguration annotation. Or, you can. The unit test MyBatisAngelWangTest. class directly inherits from AbstractTestNGSpringContextTests. Reduces a layer.
@ContextConfiguration("/config/Spring-db.xml")@Transactional@ActiveProfiles("test")publicclassMyBatisAngelWangTestextendsAbstractTransactionalTestNGSpringContextTests{}
3. Dedicated spring configuration file for supply unit test: spring-datasource-dbunit.xml
<? Xml version = "1.0" encoding = "UTF-8"?> <Beansxmlns = "http://www.springframework.org/schema/beans" xmlns: xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns: tx = "http://www.springframework.org/schema/tx" xsi: schemaLocation = "http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.2.xsd" default-autowi Re = "byName"> <description> spring-datasource-configuration </description> <beanclass = "com. angel. context. ApplicationContextAwareHelper"/> <! -- Define the Transaction Manager (declarative transaction) --> <beanid = "transactionManager" class = "org. springframework. jdbc. datasource. dataSourceTransactionManager "> <propertyname =" dataSource "ref =" dataSource "/> </bean> <tx: annotation-driventransaction-manager = "transactionManager"/> <beanid = "propertyConfigurer" class = "org. springframework. beans. factory. config. preferencesPlaceholderConfigurer "> <propertyname =" locations "> <list> <value> classpath *: prop S/performance_dev.properties </value> </list> </property> </bean> <beanid = "dataSource" class = "org. springframework. jdbc. datasource. driverManagerDataSource "> <propertyname =" driverClassName "value =" $ {jdbc. driver} "/> <propertyname =" url "value =" $ {jdbc. dbunit. url} "/> <propertyname =" username "value =" $ {jdbc. user} "/> <propertyname =" password "value =" $ {jdbc. password} "/> </bean> <! -- MyBatis configuration --> <beanclass = "org. mybatis. spring. mapper. mapperScannerConfigurer "> <propertyname =" basePackage "value =" com. angel. *. dao "/> <propertyname =" sqlSessionFactoryBeanName "value =" xSqlSessionFactory "/> </bean> <beanid =" xSqlSessionFactory "class =" org. mybatis. spring. sqlSessionFactoryBean "> <propertyname =" dataSource "ref =" dataSource "/> <propertyname =" typeAliasesPackage "value =" com. angel. *. entities "/> <propert Yname = "configLocation" value = "classpath: mybatis/mybatis-config.xml"/> <propertyname = "mapperLocations" value = "classpath:/com/angel/dao /*. xml "/> <propertyname =" plugins "> <array> <! -- Page interceptor --> <beanclass = "com. angel. orm. db. queryInterceptor "/> </array> </property> </bean> <tx: annotation-driventransaction-manager =" transactionManager "/> </beans>
In this way, all the databases tested are the same and there will be no mutual impact. Because the transaction is rolled back, if you do not believe it, you can submit an Insert test. After execution, you can check that no data is inserted in the database. However, in a unit test, data can be obtained by first inserting and then getting. What a magic ?!
4. Others: ApplicationContextAwareHelper. class
publicclassApplicationContextAwareHelperimplementsApplicationContextAware{privatestaticApplicationContext context;@Overridepublicvoid setApplicationContext(ApplicationContext applicationContext){context = applicationContext;}publicstaticApplicationContext getContext(){return context;}}
To obtain some beans dynamically, The ApplicationContextAwareHelper class is required. For example, if you want to splice a bean name and obtain the bean, you can use the following code to obtain it:
DruidDataSource dataSource =ApplicationContextAwareHelper.getBean("dataSource_"+ dataSources[i]);
Of course, this is not part of the unit test category. It is a bit difficult, but it is very useful. Please remember here.
V. Project Quality ManagementThrough the above steps, the unit test can be well implemented. However, unit testing is easy to say, implementation is difficult, and there is a way, but it is another thing to promote it. In Internet companies, many small projects run concurrently, and project members are also highly mobile. Similar projects are distributed in different project teams. In this way, each small project team may have its own specifications or none. Regulations, like laws, are the bottom-line and lowest-layer constraints of personal qualities. The quality of project development members is high, which may not cause confusion. When there are too many Members in the project team, it will be troublesome if the quality is uneven. In this case, the role of the project manager is required. At this time, the Project Manager can and should be specific to the development processes and specifications of each group. If a project manager does not exist in an Internet project, it can be implemented by an administrative or project management specialist. Of course, in addition to standardized unit tests, Project Quality Management also has many other methods. For details, refer to my article: http://www.cnblogs.com/wgp13x/p/4101314.html. Figure B-Quality Management shows the implementation of project quality management, which may not be detailed enough. Thank you for your encouragement!
From Wang Anqi