`
Rainbow702
  • 浏览: 1076943 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类

Junit测试含有‘启动新线程’这一操作的方法时瞬间结束的问题

阅读更多

之前写了一篇关于FutureTask的Blog: http://rainbow702.iteye.com/admin/blogs/2206301

里面的源码如下(不包含之前写好的main方法):

 

public class Preloader {

	private final FutureTask<Long> future = new FutureTask<Long>(new Callable<Long>() {
		@Override
		public Long call() throws Exception {
			Thread.currentThread().setName("Thread(3)");

			System.out.println(Thread.currentThread().getName() + ": simulate a latency ");
			try {
				Thread.sleep(5000);
			} catch (Exception e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + ": the latency is over");
			return Math.round(Math.random() * 1000);
		}
	});

	private final Thread loader = new Thread(future);

	public void start() {
		System.out.println(Thread.currentThread().getName() + ": start the loader");
		loader.start();
		System.out.println(Thread.currentThread().getName() + ": loader started");
	}

	public Long get() {
		try {
			System.out.println(Thread.currentThread().getName() + ": begin to get");
			long start = System.currentTimeMillis();
			Long result = future.get();
			System.out.println(Thread.currentThread().getName() + ": got result: " + result);
			System.out.println(Thread.currentThread().getName() + ": spent time: "
					+ (System.currentTimeMillis() - start));
			return result;
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + ": got nothing");
		return null;
	}
}

 当时写好的JUnit测试代码如下:

 

 

public class PreloaderTest {

	/**
	 * Test method for {@link com.rainbow.util.futuretask.Preloader#get()}.
	 */
	@Test
	public void testGet() {
		Thread.currentThread().setName("Thread(main)");
		final Preloader pl = new Preloader();
		pl.start();

		// try to get the result before the latency is over
		new Thread(new Runnable() {
			@Override
			public void run() {
				Thread.currentThread().setName("Thread(1)");
				pl.get();
			}
		}).start();

		// try to get the result after the latency is over
		new Thread(new Runnable() {
			@Override
			public void run() {
				Thread.currentThread().setName("Thread(2)");
				try {
					Thread.sleep(6000);
					pl.get();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}).start();
	}
}

 可是这段测试代码,不管怎么运行,运行多少次,它的运行结果却怎么也不是想像中的结果,却是如下的结果:

 

 

Thread(main): start the loader
Thread(main): loader started
Thread(3): simulate a latency 
Thread(1): begin to get

 从结果看来,Thread(1)  Thread(2) Thread(3) 都没有执行完了就被结束掉了。

 

 

对这个结果很是意外,于是上网查了一下,找到如下的一段说明:

 

在多线程环境下,程序退出的条件是,所有的非Daemon线程都正常结束或者某个线程条用了system.exit方法,导致进程强行退出。在eclipse下运行Junit的类是org.eclipse.jdt.internal.junit.runner.RemoteTestRunner。通过查看这个类的main方法。如下:

public static void main(String  [] args) {
	try {
		RemoteTestRunner testRunServer= new RemoteTestRunner();
		testRunServer.init(args);
		testRunServer.run();
	} catch (Throwable   e) { 
		e.printStackTrace(); // don't allow System.exit(0) to swallow exceptions
	} finally {
		// fix for 14434
		System.exit(0);
	}
}	

显然,只要主线程结束,整个程序将会退出,这就是采用junit的时候奇怪退出程序的原因。

 

看到这段,也就明白了上面的结果了。

 

为了避免上面的这种情况,我想出来的两种方法:

① 不使用JUnit来测试,而是自己写个main方法来进行测试,就如http://rainbow702.iteye.com/admin/blogs/2206301 中那样

② 还使用JUnit,但在测试代码的最后加上sleep语句,即如下代码的最后的 sleep那样:

/**
 * 
 */
package com.rainbow.util.futuretask;

import org.junit.Test;

/**
 * @author Rainbow
 */
public class PreloaderTest {

	/**
	 * Test method for {@link com.rainbow.util.futuretask.Preloader#get()}.
	 */
	@Test
	public void testGet() {
		Thread.currentThread().setName("Thread(main)");
		final Preloader pl = new Preloader();
		pl.start();

		// try to get the result before the latency is over
		new Thread(new Runnable() {
			@Override
			public void run() {
				Thread.currentThread().setName("Thread(1)");
				pl.get();
			}
		}).start();

		// try to get the result after the latency is over
		new Thread(new Runnable() {
			@Override
			public void run() {
				Thread.currentThread().setName("Thread(2)");
				try {
					Thread.sleep(6000);
					pl.get();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}).start();

		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}

 但是这样的话,必须要正确估算出需要进行sleep的时间。  或者干脆使用不指定时间的  sleep()  。

分享到:
评论

相关推荐

    JUNIT多线程测试

    然而,随着并发编程的普及,多线程测试成为了一个不可或缺的部分,因为我们需要确保我们的程序在并行执行时能够正常工作。本篇将深入探讨如何在JUnit中进行多线程测试,以及它的重要性。 首先,理解为什么需要进行...

    有关Junit和多线程测试的问题

    `JoinPoint`可以用于等待某个线程结束,而`WaitFor`则允许在满足特定条件时才继续执行测试的后续部分。这些工具使得测试更加可控,能精确地模拟多线程环境中的并发行为。 此外,GroboUtils还提供了`...

    Junit测试Void方法

    然而,对于 `void` 类型的方法,它们通常用来执行某些操作而不返回任何值,这意味着我们无法获取到一个可以用于比较的具体返回值。因此,直接使用 Junit 的 `assertEquals` 或其他类似的断言方法来进行测试是不可行...

    Java多线程Junit测试GroboUtils-5.zip

    1. **线程控制**:提供类或方法来启动、停止、等待或中断线程,以便在测试中精确控制多线程的执行顺序。 2. **同步辅助**:包含一些实用工具,帮助在测试中设置和解除锁,或者管理信号量,确保测试的可预测性。 3. *...

    Junit测试案例使用

    8. 命令模式:利用 TestCase 定义一个子类,在这个子类中生成一个被测试的对象,编写代码检测某个方法被调用后对象的状态与预期的状态是否一致,进而断言程序代码有没有 bug。 9. Junit 测试的步骤:例如,我们要...

    junit测试private函数

    需要注意的是,虽然反射提供了一种测试私有方法的途径,但这并不意味着我们应该频繁地这样做。私有方法通常是内部实现细节,如果它们对外部有直接影响,可能需要重新考虑设计。测试私有方法可能表明模块化和封装不够...

    Junit 单元测试完整案例

    2. `@RunWith(SpringRunner.class)`:这是一个JUnit runner,它使得Spring TestContext Framework可以驱动测试执行。 3. `@SpringBootTest`:这个注解用于启动一个Spring应用上下文,可以指定配置类、web环境等。 ...

    自动饮料机Junit测试(软件测试与质量保证实验).rar

    单元测试是一种针对程序代码最小可测试单元进行验证的方法,通常这个单元是函数或方法。Junit是Java领域广泛使用的单元测试框架,它提供了一套简洁易用的API,便于开发者编写和执行测试。 **Junit测试框架** Junit...

    Junit 计算器测试

    本文将针对"Junit计算器测试"这一主题,详细讲解如何使用Junit来测试一个简单的计算器应用。 首先,让我们理解一下Junit的基本概念。Junit是一个开源项目,它提供了一组用于编写和运行可重复的、自动化的测试的类库...

    junit测试案例程序

    JUnit是Java编程语言中最常用的单元测试框架之一,它允许开发者编写可重复运行的测试用例,以确保代码的正确性和稳定性。在这个“junit测试案例程序”中,我们可以找到一些基本的JUnit测试用例示例,这对于初学者来...

    junit测试工具以及安装方法

    1. **测试类与测试方法**:在JUnit中,我们通常创建一个公共类来包含所有测试用例,每个测试用例是一个公共的无参方法,用`@Test`注解标记。 2. **断言**:断言是测试的核心,例如`assertEquals()`用于检查两个值...

    实验5 JUnit测试框架的使用.doc

    在这个示例中,我们将学习如何使用 JUnit 来测试一个方法的多种情况。首先,添加一个类 WordDealUtil,包含一个方法 wordFormat4DB(),该方法的实现见文件注释。然后,编写单元测试代码,使用 JUnit 来测试该方法的...

    junit测试小例子

    除了`@Test`,JUnit还包含其他注解,如`@Before`和`@After`,它们分别用于在每个测试用例开始前和结束后执行一段代码。这对于设置和清理测试环境非常有用。例如,可以使用`@Before`初始化数据库连接,然后在`@After`...

    junit测试测试代码

    JUnit是Java编程语言中最常用的单元测试框架之一,它允许开发者编写可重复运行的测试用例,以确保代码的功能正确性。在软件开发过程中,单元测试是至关重要的,因为它们可以帮助发现早期错误,提高代码质量,并简化...

    junit测试_java_JUnit_JUnit测试_

    例如,文件可能会讲解如何设置一个基本的JUnit测试类,通常这个类会继承自`junit.framework.TestCase`(对于较旧的JUnit版本)或者使用注解`@RunWith(JUnit4.class)`(对于JUnit 4及以上版本)。 测试类中的每个...

    junit测试用例calculate

    需要将 JUnit4 单元测试包引入项目中,然后在 Eclipse 的 Package Explorer 中右键点击 Calculator 类,选择“New à JUnit Test Case”,系统将自动生成一个新类 CalculatorTest,里面包含一些空的测试用例。...

    JUnit测试代码示例

    JUnit是Java编程语言中最常用的单元测试框架之一,它允许开发者编写可执行的测试用例来验证代码的功能。在本文中,我们将深入探讨JUnit的核心概念、关键特性以及如何使用JUnit3进行测试。 首先,理解单元测试的概念...

    Junit测试jar包

    1. **创建测试类**:首先,你需要创建一个测试类,这个类通常以`Test`结尾,并且继承自`junit.framework.TestCase`(对于JUnit4)或使用`@org.junit.Test`注解(对于JUnit5)标记测试方法。 2. **测试方法**:测试...

Global site tag (gtag.js) - Google Analytics