How to Use Purpose-specific APIs¶
This section describes how to use purpose-specific APIs.
- To acquire input parameters and expected values for return values, etc. from an Excel file
- To execute the same test method with different test data
- To describe the data of multiple test cases on a single sheet
- To fix the system date and time to a value of your choice
- To test the numbering that uses sequence objects
- To configure user ID, request ID, etc. in ThreadContext
- To read an Excel file in any directory
- To perform common processing before and after executing a test.
- To use transactions other than the default
- To use this framework without inheriting its class
- To validate the properties of a class
- To enter whitespaces, line feeds and nulls in test data
- To write a blank row in test data
- To conduct a test by changing the master data
- To change the directory from which test data is read
- To add a routine conversion process for test data in the messaging process
To acquire input parameters and expected values for return values, etc. from an Excel file¶
It is possible to describe the arguments when you call a method of the class to be tested or return values of the method in an Excel file. The described data can be acquired in List-Map format (List<Map<String, String>> format).
- When acquiring data in this format, the data type LIST_MAP is used.
- LIST_MAP=<SETUP_TABLE[case_001]=EMPLOYEE_TABLE that is unique in the sheet (any string)
The second row of data is interpreted as a Map Key. After the third row of data is interpreted as a Map Value.
Data can be acquired from an Excel file in Map or List-Map format using the following methods: Specify sheet name in the first argument, and ID in the second argument.
TestSupport#getListMap(String sheetName, String id)
DbAccessTestSupport#getListMap(String sheetName, String id)
Example of test source code implementation¶
public class EmployeeComponentTest extends DbAccessTestSupport { // <Middle is omitted> public void testGetName() { // Acquire data from Excel file List<Map<String, String>> parameters = getListMap("testGetName", "parameters"); Map<String, String>> param = parameters.get(0); // Acquire arguments and expectations String empNo = parameter.get("empNo"); String expected = parameter.get("expected"); // Invoke a test method EmployeeComponent target = new EmployeeComponent(); String actual = target.getName(empNo); // Confirmation of results assertEquals(expected, actual); // <Rest is omitted> }
Example of Excel file description¶
LIST_MAP=parameters
empNo | expected |
---|---|
CHAR(4) | Yamada Taro |
Yamada Taro | Ichiro Suzuki |
The objects that can be acquired in the above table are equivalent to the list that can be fetched by the following code.
List<Map<String, String>> list = new ArrayList<Map<String, String>>(); Map<String, String> first = new HashMap<String, String>(); first.put("empNo","CHAR(4)"); first.put("expected", "Yamada Taro"); list.add(first); Map<String, String> second = new HashMap<String, String>(); second.put("empNo","Yamada Taro"); map.put("expected", "Suzuki Ichiro"); list.add(second);
To execute the same test method with different test data¶
If you want to execute the same test method with different test data, use a loop to run the test with the above-mentioned List-Map acquiring method. This allows you to increase the data variation simply by adding Excel data.
In the following example, multiple tests are executed using a single method using the above-mentioned List-Map format.
Example of test source code implementation¶
public class EmployeeComponentTest extends DbAccessTestSupport { // <Middle is omitted> public void testSelectByPk() { // Preparation data input setUpDb("testSelectByPk"); // Acquire data from Excel file List<Map<String, String>> parameters = getListMap("testGetName", "parameters"); for (Map<String, String> param : parameters) { // Acquire arguments and expectations String empNo = parameter.get("empNo"); String expectedDataId = parameter.get("expectedDataId"); // Invoke a test method EmployeeComponent target = new EmployeeComponent(); SqlResultSet actual = target.selectByPk(empNo); // Confirmation of results assertSqlResultSetEquals("testSelectByPk", expectedDataId, actual); } }
Example of Excel file description¶
// Data to loop
LIST_MAP=parameters
empNo | expectedDataId |
---|---|
CHAR(4) | expected01 |
Yamada Taro | expected02 |
// Database preparation data
SETUP_TABLE=EMPLOYEE
NO | NAME |
---|---|
CHAR(4) | Yamada Taro |
Yamada Taro | Ichiro Suzuki |
// Expected data 1
LIST_MAP=expected01
NO | NAME |
---|---|
CHAR(4) | Yamada Taro |
// Expected data 2
LIST_MAP=expected02
NO | NAME |
---|---|
CHAR(4) | Yamada Taro |
Important
To test the update process, call the setUpDb method in a loop. If this is not done, then the success or failure of the test would depend on the order of the data.
To describe the data of multiple test cases on a single sheet¶
If there are many test cases for a single test method to be tested, then there is a concern that writing one test case per sheet will increase the number of sheets, thereby decreasing maintainability.
Assigning information (Group SETUP_TABLE[case_001]=EMPLOYEE_TABLE) for grouping of table data allows the data of multiple test cases to be included on a single sheet.
The supported data type is as follows.
- EXPECTED_TABLE
- SETUP_TABLE
The format is as follows.
Data type[Group SETUP_TABLE[case_001]=EMPLOYEE_TABLE] = Table <Omitted>
For example, describe as follows when putting the data of two types of test cases (case_001, case_002) together.
In the test class, the argument Group ID is passed to the overload method with the same name as the above-mentioned API. This allows only the data of the specified Group ID to be processed.
Example of test source code implementation¶
// Registering data in DB (only the data with Group ID "case_001" will be registered) setUpDb("testUpdate", "case_001"); // Confirmation of results (only the data with Group ID "case_001" will be considered for assertion) assertTableEquals("Confirmation of database results", "testUpdate", "case_001");
Example of Excel file description¶
// Case 001: Change the department of employees.
SETUP_TABLE[case_001]=EMPLOYEE_TABLE
ID | EMP_NAME | DEPT_CODE |
---|---|---|
// CHAR(5) | VARCHAR(64) | CHAR(4) |
00001 | Yamada Taro | 0001 |
00002 | Tanaka Ichiro | 0002 |
EXPECTED_TABLE[case_001]=EMPLOYEE_TABLE
ID | EMP_NAME | DEPT_CODE | |
---|---|---|---|
// CHAR(5) | VARCHAR(64) | CHAR(4) | |
00001 | Yamada Taro | 0001 | |
00002 | Tanaka Ichiro | 0010 | //Update |
//Case 002: Change the name of employees.
SETUP_TABLE[case_002]=EMPLOYEE_TABLE
ID | EMP_NAME | DEPT_CODE |
---|---|---|
// CHAR(5) | VARCHAR(64) | CHAR(4) |
00001 | Yamada Taro | 0001 |
00002 | Tanaka Ichiro | 0002 |
EXPECTED_TABLE[case_002]=EMPLOYEE_TABLE
ID | EMP_NAME | DEPT_CODE | |
---|---|---|---|
// CHAR(5) | VARCHAR(64) | CHAR(4) | |
00001 | Satou Taro | 0001 | //Update |
00002 | Tanaka Ichiro | 0002 |
Note¶
When describing data with multiple Group IDs, the data should be described in groups based on the Group IDs, same as Describing data by grouping together based on data types when using multiple data types. If the data is not described in groups based on the Group IDs, then reading of the data is aborted in the middle and the test is not executed correctly.
To fix the system date and time to a value of your choice¶
In the case of items such as registration date and time, or update date and time, for which system date is set, it is not possible to check with an automated test that the set value is correct since the expected result changes depending on the date when the test is routinely executed. Therefore, this framework provides a function to configure a fixed value for the system date.By using this function, it is possible to check with an automated test that the set value is correct, even for items having system date set.
In the Nablarch Application Framework, the implementation class of the SystemTimeProvider interface provides the system date and time. By replacing this implementation class with a testing class that returns a fixed value, it is possible to return the system date and time of your choice.
Configuration file example¶
In the component configuration file, specify FixedSystemTimeProvider at the place where implementation class of the SystemTimeProvider interface is specified, and configure the date and time of your choice as its property. For example, configure as follows when the system date and time is September 14, 2010 12:34:56.
<component name="systemTimeProvider"
class="nablarch.test.FixedSystemTimeProvider">
<property name="fixedDate" value="20100913123456" />
</component>
property name | Settings |
---|---|
fixedDate |
|
// Acquire system date and time
SystemTimeProvider provider = (SystemTimeProvider) SystemRepository.getObject("systemTimeProvider");
Date now = provider.getDate();
To test the numbering that uses sequence objects¶
When sequence objects are used for numbering values, it is not possible to set an expected value since the value that will be numbered next cannot be predicted in advance. Therefore, this framework provides a function to replace the numbering process that uses sequence objects, with table numbering, simply by a change in the configuration file. By using this function, it is possible to check that the numbering is done correctly.
The procedure is as follows:
(1) Set up preparation data in a table.(2) Set the expected values based on the values configured in the table.
Configuration example and use case are shown below.
Configuration file example¶
In this example, it is assumed that the sequence object numbering is defined in the configuration file for production, as follows:
<!-- Configuration of numbering that uses sequence objects --> <component name="idGenerator" class="nablarch.common.idgenerator.OracleSequenceIdGenerator"> <property name="idTable"> <map> <entry key="1101" value="SEQ_1"/> <!-- For ID1 numbering --> <entry key="1102" value="SEQ_2"/> <!-- For ID2 numbering --> <entry key="1103" value="SEQ_3"/> <!-- For ID3 numbering --> <entry key="1104" value="SEQ_4"/> <!-- For ID4 numbering --> </map> </property> </component>
In this case, in the configuration file for testing, the above configuration for production is overwritten by the configuration for table numbering.
<!-- Replace numbering configuration that uses sequence objects, with numbering configuration that uses tables --> <component name="idGenerator" class="nablarch.common.idgenerator.FastTableIdGenerator"> <property name="tableName" value="TEST_SBN_TBL"/> <property name="idColumnName" value="ID_COL"/> <property name="noColumnName" value="NO_COL"/> <property name="dbTransactionManager" ref="dbTransactionManager" / > </component>Tip
For more information about setting values for table numbering, see IdGenerator.
Example of Excel file description¶
We will explain based on an example when testing a numbering process where the ID to be numbered is 1101.
// Preparation data// Numbering tableSETUP_TABLE=TEST_SBN_TBL
ID_COL NO_COL 1101 100 Tip
Configure the preparation data in the table for numbering. In the preparation data, configure only those records with the ID to be numbered and are within testing scope.
// Expected value// Numbering tableEXPECTED_TABLE=TEST_SBN_TBL
ID_COL NO_COL 1101 101 // Expected value// Table in which the numbered values are registered (the numbered value is registered in USER_ID.)EXPECTED_TABLE=USER_INFO
USER_ID KANJI_NAME KANA_NAME 0000000101 Kanji name Kana name Tip
In this example, it is assumed that the numbering process is done only once in the test. Therefore, the expected value is “the value in the preparation data + 1”.
To configure user ID, request ID, etc. in ThreadContext¶
In the Nablarch Application Framework, user IDs and request IDs are usually configured in advance in ThreadContext. In the case of automated testing of database access classes, values are not configured in ThreadContext since the class to be tested is invoked directly from the test class without going through the framework.
You can configure the values in ThreadContext by describing the values to be configured in an Excel file and calling the following methods:
TestSupport#setThreadContextValues(String sheetName, String id)
DbAccessTestSupport#setThreadContextValues(String sheetName, String id)
Tip
In particular, when registering and updating the database using automatically configured items, it is necessary that the request ID and user ID are configured in ThreadContext. These values should be configured to ThreadContext before invoking the class to be tested.
Example of test source code implementation¶
public class DbAccessTestSample extends DbAccessTestSupport { // <Middle is omitted> @Test public void testInsert() { // Configure the value for ThreadContext (specify the sheet name and ID) setThreadContextValues("testSelect", "threadContext"); // <Rest is omitted>
Test data description example¶
Describe the data as follows in the sheet [testInsert]. (ID is optional)
LIST_MAP=threadContext
USER_ID | REQUEST_ID | LANG |
---|---|---|
U00001 | RS000001 | ja_JP |
To read an Excel file in any directory¶
If an Excel file exists in the same directory as the test source code, it can be read simply by specifying the sheet name, however, if you want to read a file in a different directory, and the file can be acquired directly by using the TestDataParser implementation class directly.
An example of reading data from the file “Buz.xlsx”, which exists under “/foo/bar/” is shown below.
Example of test source code implementation¶
TestDataParser parser = (TestDataParser) SystemRepository.getObject("testDataParser"); List<Map<String, String>> list = parser.getListMap("/foo/bar/Baz.xlsx", "sheet001", "params");
To perform common processing before and after executing a test.¶
By using the annotations (@Before, @After, @BeforeClass, and @AfterClass) provided in JUnit4, it is possible to execute common processing before and after executing a test.
Note¶
The following points must be noted when using the above annotations.
Points to be noted when using @BeforeClass and @AfterClass¶
- A method with the same name and the same annotations as the superclass must not be created in the subclass. If methods having the same name are assigned the same type of annotations, then the method of the superclass is not invoked.
public class TestSuper { @BeforeClass public static void setUpBeforeClass() { System.out.println("super"); // Not displayed. } } public class TestSub extends TestSuper { @BeforeClass public static void setUpBeforeClass() { // Override the superclass methods } @Test public void test() { System.out.println("test"); } }
When the above TestSub is executed, “test” will be displayed.
To use transactions other than the default¶
When carrying out the unit test of a database access class, invoke the database access class from the test class. Normally, since transaction control is not performed in the database access class, it is required to control the transaction in the test class.
Since transaction control is a routine process, a mechanism for transaction control is provided in the testing framework.If the transaction name is described in the property file, the testing framework will start the transaction before executing the test method and end the transaction after the test method ends. This mechanism eliminates the need to explicitly start the transaction before executing a test in individual tests.Also, the transaction is ended without fail.
- The procedure to use this function is as follows:
- Inherit DbAccessTestSupport in the test class (This will automatically call the @Before and @After methods of the superclass).
To use this framework without inheriting its class¶
Normally, when a test class is created, the superclass provided in this framework can be inherited, however, there are cases where the superclass of this framework cannot be inherited as it is necessary to inherit other classes, and so on. In such cases, substitution is possible by instantiating the superclass of this framework and delegating the process.
If delegation is used, it is necessary to pass a Class instance of the test class itself to the constructor. In addition, preprocessing (@Before) and postprocessing (@After) methods need to be called explicitly.
Example of test source code implementation¶
public class SampleTest extends AnotherSuperClass { /** DbAcces test support */ private DbAccessTestSupport dbSupport = new DbAccessTestSupport(getClass()); /** Preprocessing */ @Before public void setUp() { // Launch DbSupport pre-processs dbSupport.beginTransactions(); } /** Post-processing */ @After public void tearDown() { // Launch DbSupport post-process dbSupport.endTransactions(); } @Test public void test() { // Preparation data input to database dbSupport.setUpDb("test"); // <Middle is omitted> dbSupport.assertSqlResultSetEquals("test", "id", actual); } }
To validate the properties of a class¶
Verification of properties of the class to be tested can be implemented easily.
How to describe test data is described in the same way as To acquire input parameters and expected values for return values, etc. from an Excel file.
The data implies the property name in the second row and property value to be used at the time of verification from the third row onward.
With the following methods, it can be verified that the property value is the same as the data described in an Excel file. The first argument is the message to be displayed in case of an error, the second is the sheet name, the third is the ID, and the fourth is the class, an array of classes, or a list of classes to be verified.
HttpRequestTestSupport#assertObjectPropertyEquals(String message, String sheetName, String id, Object actual)
HttpRequestTestSupport#assertObjectArrayPropertyEquals(String message, String sheetName, String id, Object[] actual)
HttpRequestTestSupport#assertObjectListPropertyEquals(String message, String sheetName, String id, List<?> actual)
Example of test source code implementation¶
public class UserUpdateActionRequestTest extends HttpRequestTestSupport { @Test public void testRW11AC0301Normal() { execute("testRW11AC0301Normal", new BasicAdvice() { @Override public void afterExecute(TestCaseInfo testCaseInfo, ExecutionContext context) { String message = testCaseInfo.getTestCaseName(); String sheetName = testCaseInfo.getSheetName(); UserForm form = (UserForm) context.getRequestScopedVar("user_form"); UsersEntity users = form.getUsers(); // Validate the properties kanjiName, kanaName, and mailAddress of users. assertObjectPropertyEquals(message, sheetName, "expectedUsers", users); } } }
Example of Excel file description¶
LIST_MAP=expectedUsers
kanjiName | kanaName | mailAddress |
---|---|---|
Kanji name | Kana name | test@anydomain.com |
To enter whitespaces, line feeds and nulls in test data¶
For more information, see Special ways to write in a cell.
To write a blank row in test data¶
You may want to include a blank row in the test data, for example,
when you handle a file of variable length, etc.
Since all blank rows are ignored, you can write an empty string like
""
using double quotation marks of Special ways to write in a cell to represent a blank row.
In the following example, the second record is a blank row.
SETUP_VARIABLE=/path/to/file.csv
<Omitted>
name | address |
---|---|
Yamada | Tokyo |
“” | |
Tanaka | Osaka |
Tip
You do not need to fill in all the cells with ""
if you want to represent a blank line.
Only one cell of the row can be filled in.
For readability, it is recommended to enter ""
in the leftmost cell.
To conduct a test by changing the master data¶
To change the directory from which test data is read¶
In the default configuration, test data is read from under test/java
.
To change the test data directory according to the directory configuration of the project, add the following configuration to the component configuration file .[1]
Key | Value |
---|---|
nablarch.test.resource-root | Relative path from the current directory at the time of test execution Multiple entries can be separated by semicolons (;) [2] |
The configuration example shown below.
nablarch.test.resource-root=path/to/test-data-dir
If you want to read test data from multiple directories, multiple paths can be specified by separating with a semicolon. The configuration example shown below.
nablarch.test.resource-root=test/online;test/batch
[1] | To change the configuration temporarily, substitution is possible by specifying the VM argument at the time of test execution without changing the configuration file. Example |
[2] | If more than one directory is specified, the test data detected first is read if there is test data with the same name. |
To add a routine conversion process for test data in the messaging process¶
The data written in an Excel file for test data is simply converted to a byte sequence by default using the specified encoding. For example, when URL-encoded data is linked from other systems, it is necessary to write the URL-encoded data in an Excel file, but it is not practical in terms of readability, maintainability, and work efficiency.
By implementing the following interface and registering it in the system repository, you can add a routine conversion process such as URL encoding.
Interface to be implemented¶
nablarch.test.core.file.TestDataConverter
Contents registered in the system repository¶
Key | Value |
---|---|
TestDataConverter_<data type> | Class name of the class that implements the above interface. Data type is the value specified for file-type of the test data. |
Example of system repository registration¶
<!-- Test data converter definition -->
<component name="TestDataConverter_FormUrlEncoded"
class="please.change.me.test.core.file.FormUrlEncodedTestDataConverter"/>
Example of Excel file description¶
When the converter specified above is implemented to perform URL encoding for each data within the cells, it is handled in the same way as when the following data is described internally in the test framework.