[Java][junit] (1) Introduction to Java testing, basic operations of junit, usage of annotations such as @Test

Java Testing

This article takes you to get started with junit and mockito.

junit

environment and prior knowledge

Here I use IDEA, jdk11

The following foundations are required:

  • java (classes, static functions)
  • maven (know how to add dependencies with pom.xml)
  • IDEA (basic operation)

Create a new project

insert image description here

Import maven dependencies

Open pom.xml and add a few lines of junit dependencies.
insert image description here


   <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>RELEASE</version>
            <scope>test</scope>
        </dependency>

code structure

insert image description here

The current idea will automatically generate a standard project structure. The java folder in the main folder contains program files, and the java folder in test is obviously the place to store our test code.
Usually, unit tests are created in a separate source folder to keep the test code separate from the real code. The standard conventions for the Maven and Gradle build tools are:

  • src/main/java - for Java classes
  • src/test/java - for test classes

Write a demo to be tested

Let's write a simple calculator, simulate some common development problems in actual development, and test it.
insert image description here

We wrote the following code:

/**
 * @author gongfpp  https://github.com/gongfpp
 * @date 2022/8/26 9:44
 */
public class Calculator {
    
    

    private int value;

    public static int add(int a,int b){
    
    
        return a+b;
    }

    public static int sub(int a,int b){
    
    
        return a+b;
    }

    public static void main(String[] args) {
    
    
        System.out.println("yes");
    }

}


Here, when I was developing the code, I copied and pasted the subtraction (sub) code ctrl + v and added an addition (pretend), but because it was only a symbol difference, I didn’t see it (pretend I was blind, But in actual development, when the code is complex, it is really hard to see. Sometimes a waste of a day turns out to be a very low-level error. Anyone who has experienced it understands it.) Next, we will
test

write test code

It is easy for us to think of calling the written code in the main function for testing, but the program is not static. If every time a new function test is added, the original code is commented out in the main function and the test code is added every time. The test is over. Then delete the test code and restore the comments. First, it is very troublesome, second, it is very bloated, and third, it is not standardized. So we need some testing frameworks to assist us in unit testing. Unit testing refers to testing the smallest unit that can be tested, which is generally a method.
insert image description here

We create a CalculatorTest class in test/java/
to import the test annotations we need, and write a method without any execution content, and add @Test annotations on it.

/**
 * @author gongfpp  https://github.com/gongfpp
 * @date 2022/8/26 9:55
 */
import org.junit.jupiter.api.Test;
public class CalculatorTest {
    
    
    @Test
    public void test(){
    
    

    }
}

At this time, this method can be tested as an independent unit, and the green operation can be seen on the left. In this way, we avoid the complexity of running the main method every time, and each @Test method can run independently.
The result of the operation is as follows:
insert image description here

Since nothing is written here, there will only be the result of the test passing.
Great, you can't fail a test without writing test code! (Don't)

For more testing functionality, we import some static functions.

import static org.junit.jupiter.api.Assertions.*;

import static means to import the static function of the class in the following package, so that we don't need the class name when we use it.
Otherwise, we need Assertions.assertEquals() when we call; this is relatively long and unnecessary. Generally, there are only test methods in the test class, and there is no risk of duplicate names.

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class CalculatorTest {
    
    
    @Test
    public void add5_5_10(){
    
    
        assertEquals(10,Calculator.add(5,5));
    }
    
    @Test
    public void sub10_5_5(){
    
    
        assertEquals(5,Calculator.sub(10,5));
    }
}


It is recommended to use the meaning of the function name that can be seen at a glance. Here we test two use cases (cases). The assertEquals()parameters are the expected value and the actual value.
insert image description here

We can run all test cases with @Test by clicking run next to the class. The running results are as follows.
insert image description here

Clearly specify expected and actual values ​​so we can fix bugs.

In the same way, the commonly used test functions are as follows, you can see the functions in the comments:

/**
 * @author gongfpp  https://github.com/gongfpp
 * @date 2022/8/26 9:55
 */
import org.junit.jupiter.api.*;


import java.time.Duration;

import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assumptions.*;

public class CalculatorTest {
    
    
    @Test
    public void add5_5_10(){
    
    
        assertEquals(10,Calculator.add(5,5));
    }

    @Test
    public void sub10_5_5(){
    
    
        assertEquals(5,Calculator.sub(10,5));
    }


    @Test
    public void testTrueWithTrue(){
    
    
        //某个结果必须为true,否则测试失败 这里成功
        assertTrue(true);
    }

    @Test
    @DisplayName("我的名字会代替函数名出现在测试运行窗口,你跑我一下试试")
    public void tetsTrueWithFalse(){
    
    
        //某个结果必须为true,否则测试失败 这里失败
        assertTrue(false);
    }

    @Test
    public void testThrow(){
    
    
        //运行不抛出异常,这里一般用lambda函数,在lambda内写逻辑代码,lambda固定格式 ()->{} ,这里只需要知道代码写在大括号里就行了。
        assertDoesNotThrow(()->{
    
    
            throw new Exception("AAA");
        });
    }


    @Test
    public void testTimeout1Sec(){
    
    
//        限制时间未完成执行则测试不通过,第一个函数为Duration.ofxxx ,可选秒、分钟、小时等,
        assertTimeout(Duration.ofSeconds(1),()->{
    
    
            //线程休眠4秒,这里时间限制是1秒,所以肯定运行超时,测试不通过
            Thread.sleep(4000);
        });
    }

    @BeforeEach
    public void beforeEach(){
    
    
//        BeforeEach一般是每个方法前的初始化,比如Calculator calculator = new Calculator() 这样的代码,
//        每次都要写一遍很麻烦,所以有了这个,可以理解为这里的代码会被复制黏贴到每个test函数的开头部分,不能是static
        System.out.println("每个运行方法前我出来一次  我不能是静态函数");
    }

    @BeforeAll
    public static void beforeAll(){
    
    
//        beforeAll一般是所以方法执行前的一次操作,比如LogSave("开始测试calculor类"),这样的代码,一批测试只运行一次,
//        必须是static,可以理解为先执行这里的代码,再去分别运行其他的@Test代码
        System.out.println("执行所有测试前我来一次 我必须是静态函数");
    }


    //可以代替@Test 并且跑3次,参数为运行次数
    @RepeatedTest(3)
    public void other(){
    
    
//        当参数条件为true才往下运行,否则忽略该测试
//        比如先跑一个条件方法,当满足才往下继续
        assumeTrue(false);


    }
}

Guess you like

Origin blog.csdn.net/gongfpp/article/details/126540432