“This is the 15th day of my participation in the First Gwen Challenge 2022.First challenge in 2022”

One, foreword

Vomit a first groove, attended many technical assembly and also have seen a lot of technical articles, found that most of there is a common fault, that is: will ask questions, ideas, but won’t speak concrete floor plan, so I write to make a goal, namely: to fall to the ground, try to provide a small and simple Demo for anyone interested in can quickly get started. Okay, here’s a couple of words, let’s get down to business.

In the last two articles, we first introduced the requirements function, and then explained the general framework design, today this article mainly looks at how to implement the use case management function.

  • Building a Data-driven Framework from 0 to 1 in Java Interface Testing (Requirements)
  • Step into Java Interface Testing: Building a Data-driven Framework from 0 to 1

Second, development environment

  • SUN JDK1.8 or above
  • Maven 3.5.4 and above
  • IntelliJ IDEA 2018 and above
  • windows/macOS
  • There is no limit on the Git
  • MySQL 5.7 and above
  • Navicat Premium 11.2.7 and above or SQLyog 11.3 and above

3. Create a Spring Boot project

The IDE used here isIntelliJ IDEA 2018:Import package and configure POM.xml:

<dependencies>
        <! MyBatis, database driver, database connection pool -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.1</version>
        </dependency>

        <! - MySQL driver - >
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <! Testng -->
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>6.14.3</version>
            <scope>compile</scope>
        </dependency>
        
    </dependencies>
Copy the code

Four, the whole code skeleton structure

├ ─ logs │ └ ─ spring - the boot - logback# log file│ all_api - test - logback. Log# all logs│ err_api - test - logback. Log# error log├ ─ SRC │ ├ ─ the main │ │ ├ ─ Java │ │ │ └ ─ com │ │ │ └ ─ zuozewei │ │ │ └ ─ springbootdatadrivendemo │ │ │ │ SpringbootDataDrivenDemoApplication.java# start class│ │ ├─ │ │ ├─ DB │ │ ├─ AutoMyBatis Generator generates data layer code, can be deleted at any time to regenerate│ │ │ ├─ Mapper# the DAO interface│ │ ├ ─ garbage# the Entity entities│ │ ├ ─ garbage manual# Store custom data layer code, including extensions to MyBatis Generator automatic generation code│ │ ├─ Mapper# the DAO interface│ │ ├ ─ garbage# the Entity entities│ │ │ ├ ─ handler# Data conversion│ │ │ └ ─ service# Business logic│ │ │ └ ─ impl# implementation class│ │ ├ ─ garbage ─resources │ ├ ─ applicationGlobal configuration file│ │ │ generatorConfig. XML# Mybatis Generator configuration file│ │ │ logback - spring. XML# logback configuration file│ │ │ spy. The properties# P6Spy configuration file│ │ │ │ │ ├ ─ db │ │ ├ ─ mapper │ │ │ └ ─ com │ │ │ └ ─ zuozewei │ │ │ └ ─ springbootdatadrivendemo │ │ │ └ ─ db │ │ │ ├ ─ autoMyBatis Generator generates data layer code, can be deleted at any time to regenerate│ │ ├ ─ ├ ─ garbage# Database Mapping file│ │ │ ├ ─ ├ ─ imp# Store custom data layer code, including extensions to MyBatis Generator automatic generation code│ │ │ └ ─ mapper# Database Mapping file│ │ └ ─ testng │ │ │ APICollection - TestSuite. XMLSet of test cases used│ │ └ ─ jdbcbapi │ │ jdbcAPI - TestSuite. XMLA set of API test cases│ │ │ └ ─test│ ├ ─ 0├ ─ Java │ ├ ─ Java │ ├ ─ Java │ ├ ─ Java │ ├ ─Interface test cases├ ─ pom. XMLCopy the code

Test case management

MySQL database

Create test case table:

CREATE DATABASE / *! 32312 IF NOT EXISTS*/`autotest` / *! 40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_vietnamese_ci */;

USE `autotest`;

/*Table structure for table `api_testdata_demo` */

DROP TABLE IF EXISTS `api_testdata_demo`;

CREATE TABLE `api_testdata_demo` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT 'test ID',
  `Protocol` enum('Http'.'RPC'.'jdbc') DEFAULT NULL COMMENT 'agreement',
  `Category` enum('Webapi'.'db') DEFAULT NULL COMMENT 'Interface Type',
  `Method` varchar(128) DEFAULT NULL COMMENT 'Interface name',
  `Parameters` varchar(1000) DEFAULT NULL COMMENT 'parameters',
  `expected` varchar(128) DEFAULT NULL COMMENT 'Checkpoint',
  `description` varchar(1000) DEFAULT NULL COMMENT 'description',
  `isRun` enum('1'.'0') DEFAULT NULL COMMENT 'Running status, 1: running, 0: not running'.PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

/*Data for the table `api_testdata_demo` */

insert  into `api_testdata_demo`(`id`,`Protocol`,`Category`,`Method`,`Parameters`,`expected`,`description`,`isRun`) values (1.'jdbc'.'db'.'demo'.'latte'.'CNY 25.00'.'test demo'.'1');
Copy the code

The creation will look something like this:

The SQL here mainly determines which test cases are selected for testing:

SELECT * FROM autotest.api_testdata_demo
WHERE Protocol = 'jdbc'
AND Category = 'db'
AND Method = 'demo'
AND isRun = 1;
Copy the code

Note: SQL fetchcases are very flexible, and you can adjust the table structure for your business.

2. Persistence layer development

Here we use Mybatis to query the test case data directly using native SQL.

MyBatis is an excellent persistence layer framework that supports customized SQL, stored procedures, and advanced mapping. MyBatis avoids almost all of the JDBC code and manual setting of parameters and fetching result sets. MyBatis can use simple XML or annotations to configure and map native types, interfaces, and Java’s Plain Old Java Objects (POJOs) to records in the database.

2.1, Mapper XML

Write the corresponding testDatamapper.xml:


      
<! DOCTYPEmapper PUBLIC "- / / mybatis.org//DTD Mapper / 3.0 / EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.zuozewei.springbootdatadrivendemo.db.manual.mapper.TestDataMapper" >

    <! SQL > alter table SQL > alter table SQL
    <select id="selectBysql" parameterType="String"   resultType="java.util.LinkedHashMap">
	    ${value};
	</select>
	
</mapper>
Copy the code

Note:

  • This is what we’re using hereThe ${}Rather than# {}That’s because if we use# {}MyBatis will automatically help us put our fields in single quotes automatically, using ‘The ${}It will not;
  • usejava.util.LinkedHashMapAs a return type, you can preserve the original field order of the result set.

2.2. Dao interface

Add testDatamapper.java to dao layer:

/** * Description: * Custom SQL query **@author zuozewei
 * @createThe 2019-11-21 * / lift

public interface TestDataMapper {

	// Customize SQL queries
	List<LinkedHashMap<String, Object>> selectBysql(String sql);

}
Copy the code

Service interface TestDataService:

/** * Description: TestDataService **@author zuozewei
 * @createThe 2019-11-21 18:00 * /

public interface TestDataService {

    // Customize the query
    List<LinkedHashMap<String, Object>> selectBysql(String sql);

}

Copy the code

Implement the interface call method of Service:

/** * Description: Parameterized custom query implementation class **@author zuozewei
 * @createThe 2019-11-21 16:04 * /


@Service
public class TestDataServiceImpl implements TestDataService {

    @Resource
    private TestDataMapper testDataMapper;

    @Override
    public List<LinkedHashMap<String, Object>> selectBysql(String sql) {
        returntestDataMapper.selectBysql(sql); }}Copy the code

To avoid null columns that cannot be saved to the LinkedHashMap object, mybatis needs to be configured as follows in the application-yml configuration file:

mybatis:
  configuration:
    call-setters-on-nulls: true Call setter NULL, return null must also be set to bean (directly execute SQL specific)
Copy the code

3. Parameterize the script

Script parameterization mainly uses @dataProvider & testng.xml of TestNG

First we create a testng configuration file under resource:

<! DOCTYPEsuite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name="The JDBC test" verbose="1" preserve-order="true" >

<test name="The test demo" preserve-order="true">
    <parameter name="sql"
               value="SELECT * FROM autotest.api_testdata_demo WHERE Protocol = 'jdbc' AND Category = 'db' AND Method = 'demo' AND isRun = 1; "/>

    <classes>
        <class name="com.zuozewei.springbootdatadrivendemo.demo.TestMapperService"/>
    </classes>
</test>

<! --<listeners>-->
<! --<listener class-name="com.zuozewei.springbootdatadrivendemo.demo.listener.ExtentTestNGIReporterListener"/>-->
<! --</listeners>-->
</suite>
Copy the code

Explain the configuration file:

  • SQL, which mainly determines which test cases are selected for testing.
  • A tag, representing a set of tests, can be written to multiple tags.
  • “Listener” is used to generate a report at the end.

Write the script testmapPerservice.java:

@SpringBootTest
@Slf4j
public class TestMapperService extends AbstractTestNGSpringContextTests {

    private String sql; / / SQL parameter

    @Autowired
    private TestDataService testDataService;

    @Parameters({"sql"})
    @BeforeClass
    public void beforeClass(String sql) {
        this.sql = sql;
    }

    /** * SQL in XML determines which use cases to execute and how many to execute. SQL searches for test cases to test */

    @DataProvider(name = "testData")
    private Object[][] getData() {
        List<LinkedHashMap<String, Object>> results = testDataService.selectBysql(sql);
        Object[][] objects = new Object[results.size()][];
        for (int i = 0; i < results.size(); i++) {
            objects[i] = new Object[]{results.get(i)};
        }
        return objects;

    }

    @test (dataProvider = "testData",description = "Test demo")
    public void testSelect(Map<String, String> data) throws InterruptedException {
		// to do something...}}Copy the code

Note:

  • To use TestNg in SpringBoot, you must add @SpringBooTtest and inheritAbstractTestNGSpringContextTests, if not inherit AbstractTestNGSpringContextTests, will cause the @autowired cannot load a Bean.
  • @parameters ({” SQL “}) : fetch SQL statements from an XML configuration file;
  • The data source of @dataProvider is MySQL;
  • @test: Test logic place.

6. Engineering structure

Finally, the engineering structure for use case management might look something like this:

Seven, summary

In today’s article, I’ve shared a process for implementing a use case management based on the capabilities of the SpringBoot framework. In the implementation process, you need to pay attention to the following parts:

  • Using the current mainstream SpringBoot 2.2.0 as the main framework of the project;
  • Use Maven as a build project to facilitate the management of dependent JARS;
  • Centralized management of test cases using MySQL, structured data;
  • TestNG as a test framework, powerful parameterization function, easy to execute test scripts;
  • MySQL database management test cases, SQL parameterization drive use cases, to achieve the decoupling of test scripts and data;

At this point, we want to implement centralized management of interface use cases, which is also complete.