Super detailed Junit unit testing tutorial

All knowledge system articles have been included in GitHub , welcome to Star!

GitHub address: https://github.com/Ziphtracks/JavaLearningmanual

Search and follow the WeChat public account "Code Out Offer", Brother Z will send you learning welfare resources!

Junit unit testing

1. What is unit testing?

In computer programming, unit testing (English: Unit Testing), also known as module testing, is a test for correctness verification of program modules (the smallest unit of software design). The program unit is the smallest testable part of the application. Simply put, it is to test whether the stability of the data meets the expectations of the program.

Second, the importance of unit testing

Speaking of testing, why should we test the program? What benefits will testing bring to the program?

First, each of us makes mistakes. After all, people are not perfect. Making mistakes in procedures is like making mistakes in life. Mistakes are not formed in a day or two. When it needs to be changed, it can't be changed in less time. The errors in the program I talked about here are well-known bugs.

We may make mistakes inadvertently. If you find that there are errors when you check the results of the project at the final stage, it is difficult for us to find the source of the bug. We all know that it is possible that a mistake will lead to a step error.

However, the test is particularly important in our above statement. With the concept of testing, at this time when we finish a small module of the project, we first test whether the small module is correct or meets expectations. If it is wrong or does not meet expectations, we need to modify it repeatedly until it is correct or meets expectations. What I said here is the use of unit tests.

When we finish the test piece by piece and test it piece by piece, then you will find that the items are put together like a puzzle. Simply put, this is the significance of unit testing!

Disclaimer: The terminology seems too blunt, the vernacular may let you understand, please forgive me for my vernacular! Thank you!

Three, black box testing and white box testing

3.1 Black box testing

Black box testing is also called functional testing. It checks whether the program can be used normally through testing. During the test, we regarded the program as a box that couldn't be opened, and we couldn't see anything in the dark, and we didn't know how to write the internal code. That is to say, input parameters for the program without considering any internal structure and performance, and then check whether the program output (Output) is within the normal range, usually at this time we need more tests to reach a conclusion.

Features: No need for us to participate in writing any code. After passing in the parameter values, check whether the program is normal or reaches the expected value.

image-20200531202329881

3.2 White box testing

White box testing is also called structural testing. Here, white box testing is different from black box testing. During the testing process, we can regard the program as a white transparent box that can be seen. We know the code and structure inside the box. When we use white box testing, testers must check the internal structure of the program, and start by checking the logic of the program, step by step checking the incoming parameters (Input) and viewing the program's running process and output (Output) results. Finally get the test data. This is the reason why "white box testing" is called exhaustive path testing. Again, it is because we know the internal structure and code of the program to check the correctness and expected value of all structures.

Note: Unit testing is a type of white box testing!

image-20200531202615957

Fourth, unit testing ideas transfer

Here we forget about the unit test, use the usual way of our own testing to test the data, and see what shortcomings it has.

First of all, I created a calculator class and created two calculation methods in it for us to simulate and test.

package com.mylifes1110.java;

/**
 * 计算器
 */
public class Calculator {
    
    
    /**
     * 加法
     */
    public int add(int num1, int num2) {
    
    
        return num1 + num2;
    }

    /**
     * 减法
     */
    public int cut(int num1, int num2) {
    
    
        return num1 - num2;
    }
}

Then we write test classes, create objects, and test addition first.

package com.mylifes1110.java;

public class Test {
    
    
    public static void main(String[] args) {
    
    
        Calculator calculator = new Calculator();
        //测试加法
        System.out.println(calculator.add(10, 10));		//20		正确
    }
}

After the test, we check that the result is correct, and then proceed to the next test. Because we have two pieces of data to test, usually after testing one piece of data, we need to comment out the tested data before proceeding to the next test. as follows:

package com.mylifes1110.java;

//测试类
public class Test {
    
    
    public static void main(String[] args) {
    
    
        Calculator calculator = new Calculator();
        //测试加法
//        System.out.println(calculator.add(10, 10));		//20		正确
        //测试减法
        System.out.println(calculator.cut(10, 10));			//0		正确
    }
}

After testing the two pieces of data, continue to write our project code.

In fact, have we found this troublesome? Why do I need to comment out the tested data in the previous step?

The answer is here, it is really troublesome. As for why it is commented out, it is because we need to test when we write the project code. It is impossible to test so much data in the same test class. And in the tested program, the data and the data are related and affect each other. This will cause our test to be inaccurate and affect subsequent coding progress and project accuracy.

Knowing the shortcomings of the above tests, we also need to understand the idea of ​​unit testing. What characteristics does unit testing need to have to solve the trouble of the above-mentioned testing? In fact, our unit tests are also constrained by coding standards. As for coding standards, don't you go to Chapter 5?

Five, unit test coding standards

There are several coding standards for unit testing, so let’s take a small book and write it down!

  • Class name: defines the test class, the class name is composed 被测试类名Testof. For example: CalculatorTest
  • Package name: The defined test class needs to be placed in the xxx.xxx.xxx.testpackage. For example: package com.mylifes1110.test;
  • Method name: the method name Test Methods There are two ways define test测试方法and 测试方法. For example: testAdd and add
  • Return value: Because our method is only tested in the class and can be run independently, there is no need to process any return value, so it is used here void. For example: public void add();
  • Parameter list: Because our method is used for testing, the input of the parameter list is not necessary. When testing, we can pass in the required parameters to test. So here is the parameter list . For example: For example: public void add();
  • @Test annotation: The test needs to be run to complete. If we only have one main method, obviously we still need to comment out the tested ones in structure. To solve this problem, we need to add an @Testannotation above the test method to complete the test. As long as the annotation is added, this method can be run separately to complete the test.
  • @Test annotation jar package Junit4, 5: @Test annotation requires us to import the jar package to use. There are two jar packages: junit-4.13-rc-2and hamcrest-core-1.3. Here I use Junit4, unit tests and Junit5, I didn't understand the version difference. The main reason is that the test can be completed!
  • IDEA quickly imported Junit4 and 5: Friends who use IDEA, your gospel is here. We can create test classes and methods first, and then add @Testannotations above the test method . At this time, the @Test annotation displayed by IDEA is red. At this time, we use the Alt + Enterkey combination to open the import Junit unit test list, and then select Junit4 or Junit5 to confirm The import is successful! At this time, check the annotations and there will be no redness!

image-20200531213742156

Six, @Test test and Assert assertion steps

Assertion method description
assertNull(java.lang.Object object) Check if the object is empty
assertNotNull(java.lang.Object object) Check if the object is not empty
assertEquals(long expected, long actual) Check if the values ​​of long type are equal
assertEquals(double expected, double actual, double delta) Check whether the double values ​​of the specified precision are equal
assertFalse(boolean condition) Check if the condition is false
assertTrue(boolean condition) Check if the condition is true
assertSame(java.lang.Object expected, java.lang.Object actual) Check whether two object references refer to the same object (that is, whether the objects are equal)
assertNotSame(java.lang.Object unexpected, java.lang.Object actual) Check whether two object references do not refer to a unified object (that is, objects are not equal)

First, let's write the test code according to the Junit unit test specification, as follows:

image-20200531215145357

Then we will find that there is a small green triangle on the left of each method that needs to be tested, which is used for unit test operation. In other words, we can only run a certain method to test. Now we run the add() method, the result is as follows:

image-20200531224224937

At this time, we found that the console was green and printed the output, which showed that our program was fine. What will happen if I add an arithmetic exception to it? as follows:

00

Here we will find that the console turns red and gives an error message. This proves that there was a problem after our program was tested. This is only the relationship between correctness and failure of the program.

What if we need an expected value? Then the result of the test is not the expected value I want, but the program is still green, what should I do to prove that there is no problem with the program? Some friends will say that we have checked the information in the print console. If the print result is not the expected value, it means that there is a problem with the program and need to be modified. Yes, there is nothing wrong with saying that. However, when we are developing, what should we do if you see the green color due to your negligence or fatigue? So in the face of this problem, we try not to print the expected value when we are unit testing, we need to pay attention to observe that green and red are better, it can directly reflect the accuracy of the program and achieve the expected value.

At this time, we need to introduce a static method of an object to assert whether it is the expected value.

Assert.assertEquals(预期值, 结果);

image-20200531220749643

At this time, we found that the method coming out of the Assert period can assert both an array and a common data type. So at this time we will use it to assert the expected value. as follows:

image-20200531224130120

At this time, we assert that the expected value of result is 10. After the assertion, an error will be reported if the expected value is not reached!

Note: When we use assertions, try not to assert Double objects. For double-precision numbers, it is absolutely necessary to use incremental comparisons to avoid floating-point rounding problems. If you usethe 3-parameter versionassertEqualswithdoubleparameters.

assertEquals(double expected, double actual, double delta);

In this way, Doublethe boxing will be automatically canceled, doubleand everything is normal, so the test result will not fail. Otherwise, using two parameters to assert the double type, there will be the following error message:

Seven, @Before and @After annotations

We are in the above, will you find some repeated operations? For example, each of our methods needs to go to the new object. Some smart friends will say that we can put it in the class at the same level as the method. Yes, this approach is also a positive solution.

But in our Junit unit test, there is an @Before annotation, which is used as a resource application. That is, the method modified by the @Before annotation will be automatically executed before the test method. Therefore, we can define an init method to initialize the process of creating an object. This is what the @Before annotation does!

Some application scenarios, such as read and write operations of IO streams. If we want to test this code, we need a process of closing the stream. We close the stream and use the finally block to ensure the closing operation of the final stream. At this time, we have an @After annotation in the Junit unit test, which is used to close the resource. That is to say, the method modified by the @After annotation will be executed after the test method. Therefore, when we need to ensure that the resource is finally closed and destroyed, we can define a close method to close or destroy the resource. This is what the @After annotation does!

Note: @Before and @After annotations can still guarantee the initialization and shutdown of data when the program reports an error. The two methods are still executed. This is a bit like the initial phase and destruction phase of our tomact server, and their execution is not affected in any way.

image-20200531225614728

8. Customize @MyTest annotation to implement unit test

Purpose: complete the custom annotation @MyTest, and implement the method marked with the annotation and start it. (Imitate @Test annotation to do unit test)
Steps:

  1. Create a new annotation class (annotation) , named MyTest
  2. Create a TestJunit unit test class and write several methods, such as:public void test1()
  3. Create a MyTestDemo test class (main function implementation class), this class mainly uses the reflection mechanism to realize the start of the @MyTest annotation method in the TestJunit unit test class
  4. The life cycle of the annotation class is consistent with the reflection mechanism , that is, the defined annotation can be retained until runtime, and the annotation information can be obtained through the reflection mechanism
  5. Write the MyTestDemo test class, use reflection to obtain the Class object of the TestJunit unit test class, and obtain all the method objects in the unit test class, and traverse all the method objects. As long as the method annotated by @MyTest is added to execute it, it is not annotated. Give any processing operation
  6. Start the test class and view the results (execution results, at the end!)

note:

  1. In the custom annotation class, no annotation body is written, that is, no default value is given. Because the annotation only serves as an identification, the identification method needs to be activated
  2. The annotation class is also a .class file after compilation
  3. To complete the custom annotation operation through the reflection mechanism, you must give the same life cycle as the annotation and reflection
  4. You have to know that we can't complete the plug-in functions of Junit4 and Junit5, and can selectively implement the annotated method, and we have the ability to write the plug-in IDEA, which is not recognized. Will not generate run method startup items for you
MyTest annotation class
package com.mylifes1110.java.anno;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * 此自定义注解@MyTest只是作为需要单元测试的标记,不需要做默认值
 * @Retention注解表示给与@MyTest注解生命周期
 * 当前定义的注解可以保留到运行时,通过反射机制可以获取注解信息
 * 否则反射将对注解没有任何作用,失去了该意义和自定义单元测试的初衷
 */
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
    
    
//    String value() default "";
}
TestJunit unit test class
package com.mylifes1110.java.test.junit;

import com.mylifes1110.java.anno.MyTest;
import org.junit.Test;

public class TestJunit {
    
    

    @Test
    public void test1() {
    
    
        System.out.println("---test1---");
    }

    @MyTest
    public void test2() {
    
    
        System.out.println("---test2---");
    }

    @MyTest
    public void test3() {
    
    
        System.out.println("---test3---");
    }

    public void test4() {
    
    
        System.out.println("---test4---");
    }
}
MyTestDemo test class (mainly realize function and test)
package com.mylifes1110.java.test.junit;

import com.mylifes1110.java.anno.MyTest;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 让自定义的MyTest注解起作用
 * 通过反射,扫描TestJunit类中有哪些方法上方加了MyTest注解
 * 如果加@MyTest注解的则执行它
 * 如果没有加@MyTest注解的则不做任何处理
 */
public class MyTestDemo {
    
    
    public static void main(String[] args) {
    
    
        /**
         * 1.获取TestJunit类对应的Class对象
         */
        Class<TestJunit> junitClass = TestJunit.class;
        /**
         * 获取TestJunit类中所有的方法对象
         */
        Method[] methods = junitClass.getMethods();

        /**
         * 遍历所有方法对象查找有与没有@MyTest注解,并做出响应处理
         */
        for (Method method : methods) {
    
    
            boolean present = method.isAnnotationPresent(MyTest.class);
            /**
             * TestJunit类中有@MyTest注解的执行该方法
             */
            if (present) {
    
    
                try {
    
    
                    method.invoke(junitClass.newInstance());
                } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) {
    
    
                    e.printStackTrace();
                }
            } else {
    
    
                /**
                 * TestJunit类中没有@MyTest注解的不做任何操作
                 * 此else分支冗余,只是为了做标记,让你们好理解
                 */
            }
        }
    }
}
Execution result graph

Insert picture description here
Insert picture description here

Guess you like

Origin blog.csdn.net/weixin_44170221/article/details/106463482
Recommended