Dao consumer
Persistence Logic
Unit testing has become an important part of modern software development methods. Even if you disagree with the benefits of extreme programming (XP) or other agile methods, unit testing should be a basic practice in your software development lifecycle.
In terms of concept, the persistence layer can be divided into three layers, and ibatis makes unit tests on these different layers very simple, as shown in 13-1.
SQL ing
- Batis makes it easier to perform unit tests on these different layers in at least three ways:
- The mapping layer itself includes ing, all SQL statements, and the domain objects mapped.
- Test the DaO layer, which allows you to test any persistence-specific logic in the DaO layer.
- Test in the consumption layer of Dao.
13.1.1 Perform unit tests on the ing Layer
Unit Tests on the ing layer may be performed in most applications.ProgramThe lowest-level unit test occurred in. This process includes testing the SQL statements and the domain objects mapped to by these statements. This means that we will need a database instance for testing.
2. test database instances
The database instance used for testing may be a real instance created in the database management system you actually use (for example, Oracle or Microsoft SQL Server. If your environment is friendly to unit testing, you only need to modify the configuration to run the unit test. If you plan to use non-standard database features (such as stored procedures), it may be necessary to use real database instances. The selection of stored procedures and some other non-portable database designs makes it difficult to perform unit tests on the database unless you use a real database instance.
The disadvantage of using a real database instance is that you can perform a unit test only when you connect to the network. You can also use a local instance of a real database, but this means that additional local environment settings are required before the unit test is run. No matter which one of the two methods is used, you will face the same problem, that is, each test must re-build the test data, or even need to re-build the test suite) between modes, or between each unit test. It takes a long time to complete the above tasks even on a large enterprise-level database server. Another problem is that because the databases used are centralized, conflicts may occur when multiple developers Perform unit tests at the same time. Therefore, different database modes must be used to isolate every developer. As you can see, the common problem with this approach is that unit testing depends on a considerable amount of infrastructure, which is not perfect for developers with a majority of experienced test drivers.
Java developers are very lucky because they have at least a very good memory (in-memory) database to use, this type of database makes it easy to perform unit tests on a relatively standard database design. HSQLDB is an internal database fully written in Java. It can work normally without any files on the disk or connecting to the network. In addition, it can regenerate most database designs from typical databases (such as Oracle and Microsoft SQL Server. Even if HSQLDB cannot re-build the entire database because the design is too complex (for example, the stored procedure is used), it can re-generate the vast majority of the database. HSQLDB allows quick database reconstruction, including database mode and test data. Ibatis's unit test suite is to use HSQLDB to recreate the data library mode and test data between each individual test. We personally used HSQLDB to test the test suite consisting of nearly 1000 database-related tests. The running time was less than 30 seconds.
For more information about HSQLDB, visit http://hsqldb.sourceforge.net /. In addition, one message that may make Microsoft. NET happy is that someone has initiated HSQLDB transplantation, and someone has begun to create other memory databases.
3 2. Database scripts
Now that a database instance is available, how should we construct and create the database mode and test data? You may already have database scripts that can be used to create database models and test data. Ideally, you should include these scripts in a version control system (such as CVS or subversion. These scripts should be different from other scripts in the application.CodeIs treated equally. Even if you have no control over the database you are using, you should regularly obtain updates from those in control. ApplicationSource codeIt should always be synchronized with the database script, and the unit test is to ensure that they are synchronized. Every time you run the unit test suite, you should also run these scripts to recreate the database mode. Using this method, you can easily submit the new set required for the database creation script to the version control system, and then run the unit test to determine whether the script update has caused problems to the application. This is the ideal situation. If you use a memory relational database (such as HSQLDB) to run the test, you may need another step to convert the database mode. You can consider automating the conversion process to avoid possible errors in manual programming and speed up integration.
4 3. ibatis configuration file (for example, sqlmapconfig. XML)
For unit testing, you may want to use an independent ibatis configuration file. The configuration file is used to control the configuration of the data source and Transaction Manager. It may be completely different in the test environment and product environment. For example, a product environment may be a managed environment like a J2EE application server. In such an environment, a managed datasource instance may be retrieved from JNDI. You may also use global transactions in the product environment. However, in the test environment, your application may not run on the server. Instead, you only configure a simple datasource and use local transactions. The simplest way to configure the test environment and product environment respectively is to use different ibatis configuration files, which reference the same set of SQL ing files.
5. ibatis sqlmapclient unit test
Now all the prerequisites are ready, including the database instance, the script for automatically building the database, and the configuration file for testing. Then you can start to create a unit test. Code listing 13-1 is an example of using JUnit to create a simple unit test.
Code List 13-1 sqlmapclient unit test example
Set unit test and test data
Test a single key valuePerson object Retrieval
The sample in code list 13-1 uses the JUnit unit test framework for Java. (You can find more information about JUnit on www.junit.org. There are similar tools for. NET Framework, including nunit, which can be downloaded from www.nunit.org .) In our setup method, we first deleted the database tables involved in the test, then rebuilt them and re-filled them with test data. Rebuilding everything for each test ensures that each test is independent of each other, however, it would be too slow to perform a test on RDBMS such as oracle or SQL Server. In this case, memory relational databases such as HSQLDB can be used. In our actual test case, we read a record from the database, map it to a bean, and then assert) the values of each field in bean are the expected values.
The above is all the work required to test the ing layer. The next layer to be tested is the DaO layer. Assume that your application has the DaO layer.
13.1.2 Perform unit test on Dao
The Dao layer is an abstract layer, so according to its nature, Dao should be very easy to test. Dao also makes it easier to test Dao-layer users. This section describes how to test Dao itself. Dao is usually separated into an interface and an implementation. Since we will test Dao directly, the interface will not work. We will test the DAO implementation directly. This may be the opposite of the DAO mode, but it just shows the benefits of unit testing-It removes those bad habits from our system!
If possible, tests on the DaO layer should not involve databases and underlying infrastructure. The Dao layer is an interface for persistence implementation. However, when testing the DaO layer, we are more interested in testing the content inside the DaO layer, rather than testing anything outside the DaO layer.
The complexity of Dao testing only depends on DAO implementation. For example, it may be very difficult to test a JDBC Dao. You need a good simulation framework to replace all the typical JDBC components, such as connection, resultset, and prepared-statement. Even so, it is very troublesome to manage such complex APIs using simulated objects. It is much easier to simulate the ibatis sqlmapclient interface. Next, let's give it a try.
6. Use simulated objects to perform unit tests on Dao
A simulated object is an object used to replace an actual implementation for unit testing. Simulation objects generally do not have strong functionality; they are only used to meet a single situation, so that unit tests only focus on what they should be concerned about, without worrying about the increase in complexity. In the following example, we will use these simulated objects to demonstrate a method for testing the DaO layer.
In our example, we will use a simple Dao. We will not consider the ibatis Dao framework, so we do not need to worry about transactions and such things. The purpose of this example is to demonstrate how to test the DaO layer, no matter which Dao framework you are using (as long as it is actually used ).
First, check the DAO to be tested. Code List 13-2 provides a sqlmappersondao implementation, which calls an SQL ing file similar to the example given in section 13.1.1.
Code List 13-2 test a simple Dao
Note how we inject sqlmapclient into the DaO constructor in code listing 13-2. This provides a simple way to perform unit tests on Dao, because we only need to simulate the sqlmapclient interface. Obviously, this is a very simple example, without too many tests, but each test is very important. Code listing 13-3 shows the unit test used to simulate sqlmapclient and test the getperson () method.
Code listing 13-3 contains a persondao unit test simulating sqlmapclient
The example given in code list 13-3 uses the Java object simulation framework JUnit and jmock. As shown in the rough section of code listing 13-3, jmock is used to simulate the implementation of the sqlmapclient interface, so that we can test the DaO behavior independently without worrying about the actual implementation of sqlmapclient, therefore, you do not need to consider SQL statements, XML files, and databases related to them. Jmock is a very useful tool. You can find more information about it on www.jmock.org. As you may have guessed, there is also a simulated framework for. Net called nmock. For more information about it, see the http://nmock.org.
13.1.3 Perform unit tests on the Consumption layer of Dao
Consumers who use other layers of the DaO layer in the application are called the DaO layer (consumer ). The DAO mode allows you to test these consumer features without relying on any features of the persistence layer. A good DAO implementation should have an interface that can well describe its available functions. The key to testing the consumption layer is to obtain this interface. Evaluate the interface in code listing 13-4 and you will find the getperson () method described in the previous section.
Code List 13-4 simple Dao Interface
To start testing the consumers at the DaO layer, all you need is the interface shown in code 13-4. We don't even need a complete implementation. With jmock, we can easily simulate the behavior expected by the getperson () method. Consider the following service that uses the persondao interface (see code list 13-5 ).
Code List 13-5 services using the persondao Interface
The objective of our unit test is not Dao -- but the business logic in the getvalidatedperson () method, such as the various verifications it performs. Each verification in the method may be a private method. To facilitate the discussion, let's test only the private interface.
Thanks to the previous persondao interface, it is easy to test the getvalidatedperson () method without a database. All you need to do is simulate the implementation of the persondao interface, pass the simulation implementation to the constructor of the service, and call the getvalidatedperson () method. Code List 13-6 provides a unit test to complete the above work.
Code listing 13-6 use a simulated rather than a real Dao to avoid Database Access
We used JUnit and jmock again. As you have seen in code list 13-6, this test method is consistent across all layers of the application. This is advantageous because it can bring easy-to-maintain and concise unit tests.
We will introduce the unit tests in ibatis. In fact, there are a lot of good unit test resources on the Internet. You can search for "unit test" on Google to find many related resources, which can help you quickly improve the unit test capability, you may even find a better unit test method than the method used in this book.