junit单元测试和Main方法之多线程


遇到的问题:这两天写项目需求遇见一个大坑,代码两下写完了,测试卡了我整整一天,报错信息显示各种连接异常(oss异常或者sql异常),导致我大部分时间都陷入查找oss为什么连接不上的问题,耗费了大量时间。后来发现是单元测试时执行了异步任务的问题!把异步任务取消后,程序立马跑通了,搞了我一整天的问题终于落在帷幕,避免以后再次卡住,在此记录junit单元测试在执行多线程情况下的问题和结论,并对比junit单元测试和主程序Main方法之多线程执行。

一. 先放结论

切记junit不支持多线程!!!在junit单元测试中,当创建了新线程后,单元测试并不会等待主线程下启动的新线程是否执行结束,只要主线程结束完成,单元测试就会关闭,导致主线程中启动的新线程不能顺利执行完!

  • 对于junit单元测试,当@Test注释的单元测试方法执行时,实际上junit时将该方法作为参数传给了junit.textui.TestRunner类的main函数,并通过main函数进行执行(源代码如下)。
package junit.textui;
public class TestRunner extends BaseTestRunner {
  	//...
	public static void main(String args[]) {
        TestRunner aTestRunner = new TestRunner();
        try {
            TestResult r = aTestRunner.start(args);
            if (!r.wasSuccessful()) {
                System.exit(FAILURE_EXIT); // FAILURE_EXIT = 1
            }
            System.exit(SUCCESS_EXIT); // SUCCESS_EXIT = 0
        } catch (Exception e) {
            System.err.println(e.getMessage());
            System.exit(EXCEPTION_EXIT); // EXCEPTION_EXIT = 2
        }
    }
}
  • @Test注释的单元测试方法执行结束,TestRunner类的main函数将会调用System.exit(0)。此时如果该单元测试方法中还有其他子线程在运行,TestRunner类的main函数也会调用System.exit(0)
  • System.exit()是系统调用,用于通知系统立即结束jvm的运行。即使jvm中有线程在运行,jvm也会停止。
    • System.exit(0):表示单元测试执行成功,系统正常退出。
    • System.exit(1):表示单元测试执行失败,系统异常退出。
    • System.exit(2):表示系统异常退出。

二. junit执行多线程示例

  1. Maven依赖
<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
       </dependency>
</dependencies>
  1. 线程类
public class NumThread extends Thread {
    
    public NumThread(String name){
        super(name);
    }

    @Override
    public void run(){
        int sum = 0;
        for(int i=1;i<=100;i++){
            sum+=i;
            System.out.println(getName()+"|"+i+"|"+sum);
        }
        System.out.println("线程运行完成1");
        
        try {
            Thread.sleep(5000);
        }catch (Exception e){
            System.out.println("catch Exception");
        }
        
        System.out.println("线程运行完成2");
    }
}

  1. junit测试类
import org.junit.Test;

public class JunitTest {

    @Test
    public void test1(){
        NumThread nt1 = new NumThread("nt1");
        nt1.start();

        System.out.println("test启动完成");
    }
}

  1. 运行结果(每一次运行结果不同)
test启动完成
nt1|1|1
nt1|2|3
...
nt1|63|2016
nt1|64|2080
  1. 结论:在线程类中,循环打印100个数字,但是在junit测试类中只打印了一部分。因此当test1()主程序执行完成,不会等待子线程运行完毕,而是直接调用System.exit(0)关闭jvm。

三. Main主程序的执行示例

  1. 主程序
public class Main {
    public static void main(String[] args) {
        NumThread nt1 = new NumThread("nt1");
        nt1.start();

        System.out.println("Main方法执行完成");
    }
}

  1. 测试结果
Main方法执行完成
nt1|1|1
nt1|2|3
nt1|3|6
nt1|4|10
....
nt1|99|4950
nt1|100|5050
线程运行完成1
线程运行完成2
  • 可见,Main函数可以将数字全部打印出来。因此,Main函数会等待子线程执行完毕后,再关闭JVM。

参考资料

junit单元测试之多线程
junit 不能用于测试多线程

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值