Introduction: in all development testing, interface testing is an essential one. Effective and complete interface testing can not only guarantee the development quality of new functions, but also make the development have the ability of regression when modifying the function logic. At the same time, it is also the premise of elegant refactoring. What are the principles for writing interface tests? What should be the structure of the test code? What are the practical skills of interface testing? This paper shares the author’s experience in interface testing.
Front line developers may have more or less caused online bugs or even failures; There are also scenarios like this, where a student refactored the code when developing a function, resulting in online bugs or failures; When developing a function, we found that we need to modify the common logic, afraid of affecting other functions, so we copy the code very impolitely and rewrite a set of separate logic to support it.
The above situations all contain a key problem, whether it is function development or logic refactoring, how to ensure the quality of code development. The means of security, as everyone knows, is testing. The first is new function test to ensure the new function logic is correct; The second is regression test to ensure that the original business function logic is correct. There are two ways of testing, manual testing and automatic testing. With the continuous development of testing technology and tools, the proportion of manual testing is gradually reduced and replaced by automatic testing. Automated testing is sustainable and repeatable, even AI enabled.
1、 Test layering
The test is also layered, as shown in the figure below:
In a system, automatic test is generally divided into unit test, module test and interface test.
At present, most of my application code is based on the interface oriented programming mode of spring framework, and unit testing has been weakened. The requirement of unit testing is basically the testing of a single class and method. In our current mode, the writing cost is too high. Of course, if it is a tool or a relatively cohesive and complex logic (such as algorithmic logic), unit testing should be used to ensure the correctness of logic.
When the system is large and there are many modules, the module test layer can be established to ensure the correctness of each module function. However, the current system development trend is micro service architecture, so the module test layer is not very necessary, it can be covered by the interface test layer.
Personally, I think it should be called entrance test. This layer is to conduct integration test from the entrance of the system. Application portals are usually HSF (a distributed RPC service framework) services, messages, scheduled tasks.
As a development tool, there are tens of thousands of test methods, and interface test is indispensable. When the interface test of our application is effective and complete, it can not only guarantee the development quality of our new functions, but also enable us to have the ability of regression when modifying the function logic. At the same time, it is also the premise of our code refactoring. At the same time, testability is also an indicator of reasonable code structure. If a piece of code is difficult to write test script or cannot be tested, it means that the current code structure is unreasonable and needs to be reconstructed. Next, I will mainly talk about the effectiveness of interface testing.
2、 Test principle
- Automation: interface testing is non interactive, automated execution, and does not require human participation.
- Independence: interface tests should not be interdependent.
- Repeatable: the interface test can be repeated and not affected by the environment.
- The interface test follows BCDE principle to ensure the quality of interface delivery. Border: boundary test. Correct: correct input, correct expected output. Design: write test logic according to requirements and design documents. Error: wrong input, expected output.
- Data preparation: data preparation is carried out through system services, not through direct insertion into dB.
- Testability: code that is not testable needs to be restructured.
- Coverage: interface testing needs to cover all UC. Meanwhile, code coverage and branch coverage should reach certain standards, and new code must be covered.
- Persistence: if the code modification causes the existing interface test execution to fail, the code problem must be fixed or the code logic must be tested.
- Time requirement: the interface test should be completed before the project release, and should not be supplemented after the project release.
The above basic principles should be applicable to automatic test cases of all layers. In addition to the above principles, there are other principles to follow when writing interface tests. Let’s take a look at a diagram first
From the perspective of system, this paper analyzes the entry call, taking HSF service as an example
- The peripheral system calls the services provided by our system.
- The system executes a lot of code logic, including branch logic.
- The system relies on the external HSF service in the process of execution, calls it and gets the return value.
- In the process of execution, the system relies on DB query or landing data, and relies on cache query or landing data.
- During the execution of the system, messages are sent to the outside.
- Return HSF execution result to upstream system.
The key principle of effective interface testing is to cover all entries, mock all dependencies, and verify the traces left in the execution process
- Entry coverage: the interface test case must cover HSF service entry, message entry and timing task entry.
- Dependency mock: among the basic principles, there is the principle of repeatability, that is, interface testing cannot be dependent on the environment, and requires mocking to remove external dependencies. However, it is not recommended to completely mock DB dependencies. On the one hand, the cost of mock is high, and on the other hand, it may not cover SQL and table constraint logic.
- Verification integrity: an effective interface test should have complete verification, and the interface test without verification is meaningless. As long as the trace left in the process of execution has an impact on the business, complete verification must be carried out to ensure the effectiveness of the interface test. Verification of HSF interface return value: verify HSF return parameters according to scenarios and interface conventions. DB verification: verify the correctness of landing data. Cache check: check the correctness of the data stored in the cache. HSF relies on input parameter verification: the input parameter that depends on HSF call is obtained through mock tool, and then input parameter verification is carried out. Message verification: get the message object sent by the mock tool and verify the message body.
3、 Test code structure
When writing test code, we should also consider the readability, extensibility and reusability of the code just like writing business code. At the same time, according to the business characteristics of the system, the test components suitable for the current system can be encapsulated on the basis of the test framework, so as to improve the efficiency of test code writing and standardize the structure of test code.
The general structure of an interface test code is as follows:
1. Test preparation
Rely on data preparation
Most of the time, our test has data dependence, which may be configuration data or business data (for example, refund needs to rely on payment data).
- Configuration data: you can initialize the configuration by defining the configuration file.
- Business data: this kind of data should be generated by calling business services instead of directly inserting data.
Rely on mock
For external dependencies, you need to mock the dependent services to avoid real calls.
Preparation for interface test
Prepare input parameters of interface aspect.
2. Test execution
Call interface method to execute business logic.
3. Test verification
- Return parameter verification: verify the return parameters of the interface.
- DB: check DB landing data.
- Cache data verification: verify the data landed in the cache.
- Message verification: verify the message object sent to the outside.
- External HSF call verification: verify the input parameters of external HSF call.
4、 Practical skills
1. Implementation efficiency
For interface testing, the execution efficiency is a point that we have to pay attention to. If an interface test is executed for more than 3 minutes to see the results, it will greatly reduce the enthusiasm of developers to write interface tests. For the improvement of test execution efficiency, the proposed scheme is as follows:
- Minimize the startup test context, such as the application of spring boot, and start spring
- Use an in memory database, such as H2
- Mocking off middleware dependency
2. Test framework selection
For the testing framework, it is recommended to choose the testing framework based on TestNG, which can provide data preparation through configuration files. If you can’t find a suitable one, you can package it based on TestNG.
3. Interface test coverage
The integrity of scenarios affects the coverage of test cases. On the one hand, developers need to list normal and abnormal situations based on the input and test experience of business scenarios. On the other hand, interface methods also have some fixed points to be tested, such as idempotent test, boundary value test, parameter incorrect test and so on.
At the same time, we should also check the code or branch logic not covered by the interface through the coverage tool to carry out targeted scenario coverage testing. In my experience, complete coverage of branches is very important, especially for abnormal branches.
To ensure the stability of the system online operation, quality assurance means is essential. Although there are many automatic support means, interface testing is still one of the most basic and important support means. If the coverage and effectiveness of interface testing can be guaranteed continuously, the generation of online bugs will be reduced to a great extent, and the developers will be more active in refactoring the code.
Author: Developer Assistant_ LS
This article is the original content of Alibaba cloud and cannot be reproduced without permission