`

junit4源码浅析

    博客分类:
  • Test
阅读更多
junit3和junit4是两个非常不同的版本, 不能简单的理解为是后者是前者的一个升级, 二者的内部实现有很大的不同。 这里只针对junit4以后的版本。
所有的testcase都是在Runner下执行的, 可以将Runner理解为junit运行的容器, 默认情况下junit会使用JUnit4ClassRunner作为所有testcase的执行容器。 如果要定制自己的junit, 则可以实现自己的Runner,最简单的办法就是Junit4ClassRunner继承, spring-test, unitils这些框架就是采用这样的做法。如在spring中是SpringJUnit4ClassRunner, 在unitils中是UnitilsJUnit4TestClassRunner, 一般我们的testcase都是在通过eclipse插件来执行的, eclipse的junit插件会在执行的时候会初始化指定的Runner。初始化的过程可以在ClassRequest中找到:
	@Override
	public Runner getRunner() {
		return buildRunner(getRunnerClass(fTestClass)); 
	}

	public Runner buildRunner(Class<? extends Runner> runnerClass) {
		try {
			return runnerClass.getConstructor(Class.class).newInstance(new Object[] { fTestClass });
		} catch (NoSuchMethodException e) {
			String simpleName= runnerClass.getSimpleName();
			InitializationError error= new InitializationError(String.format(
					CONSTRUCTOR_ERROR_FORMAT, simpleName, simpleName));
			return Request.errorReport(fTestClass, error).getRunner();
		} catch (Exception e) {
			return Request.errorReport(fTestClass, e).getRunner();
		}
	}

	Class<? extends Runner> getRunnerClass(final Class<?> testClass) {
		if (testClass.getAnnotation(Ignore.class) != null)
			return new IgnoredClassRunner(testClass).getClass();
		RunWith annotation= testClass.getAnnotation(RunWith.class);
		if (annotation != null) {
			return annotation.value();
		} else if (hasSuiteMethod() && fCanUseSuiteMethod) {
			return AllTests.class;
		} else if (isPre4Test(testClass)) {
			return JUnit38ClassRunner.class; 
		} else {
			return JUnit4ClassRunner.class;
		}
	}

这里的局部变量fTestClass是当前的testcase类, 如果使用了注解, 它会从RunWith中拿到指定的Runner, 所以要定制的话, 最方便的做法就是通过@RunWith指定定制的Runner, Spring-test, Unitils都是这么干的^_^
下面来看JUnit4ClassRunner的构造器:
public JUnit4ClassRunner(Class<?> klass) throws InitializationError {
		fTestClass= new TestClass(klass);
		fTestMethods= getTestMethods();
		validate();
	}

JUnit4ClassRunner没有默认的构造器, 从构造器中我们可以看出, 它需要一个参数, 这个参数就是我们当前要运行的testcase class, Runner拿到了要执行的testcase类之后, 就可以进一步拿到需要执行的测试方法, 这个是通过注解拿到的:
	
	protected List<Method> getTestMethods() {
		return fTestClass.getTestMethods();
	}

	List<Method> getTestMethods() {
		return getAnnotatedMethods(Test.class);
	}

	public List<Method> getAnnotatedMethods(Class<? extends Annotation> annotationClass) {
		List<Method> results= new ArrayList<Method>();
		for (Class<?> eachClass : getSuperClasses(fClass)) {
			Method[] methods= eachClass.getDeclaredMethods();
			for (Method eachMethod : methods) {
				Annotation annotation= eachMethod.getAnnotation(annotationClass);
				if (annotation != null && ! isShadowed(eachMethod, results)) 
					results.add(eachMethod);
			}
		}
		if (runsTopToBottom(annotationClass))
			Collections.reverse(results);
		return results;
	}

初始化完成之后, 就可以根据拿到的Runner, 调用其run方法,执行所有的测试方法了:
	@Override
	public void run(final RunNotifier notifier) {
		new ClassRoadie(notifier, fTestClass, getDescription(), new Runnable() {
			public void run() {
				runMethods(notifier);
			}
		}).runProtected();
	}

	protected void runMethods(final RunNotifier notifier) {
		for (Method method : fTestMethods)
			invokeTestMethod(method, notifier);
	}

	protected void invokeTestMethod(Method method, RunNotifier notifier) {
		Description description= methodDescription(method);
		Object test;
		try {
			test= createTest();
		} catch (InvocationTargetException e) {
			notifier.testAborted(description, e.getCause());
			return;			
		} catch (Exception e) {
			notifier.testAborted(description, e);
			return;
		}
		TestMethod testMethod= wrapMethod(method);
		new MethodRoadie(test, testMethod, notifier, description).run();
	}

这里很多地方都利用了线程技术, 可以忽略不管, 最终都是要通过反射拿到需要执行的测试方法并调用, 最终的调用在MethodRoadie中:
	public void run() {
		if (fTestMethod.isIgnored()) {
			fNotifier.fireTestIgnored(fDescription);
			return;
		}
		fNotifier.fireTestStarted(fDescription);
		try {
			long timeout= fTestMethod.getTimeout();
			if (timeout > 0)
				runWithTimeout(timeout);
			else
				runTest();
		} finally {
			fNotifier.fireTestFinished(fDescription);
		}
	}
	
	public void runTest() {
		runBeforesThenTestThenAfters(new Runnable() {
			public void run() {
				runTestMethod();
			}
		});
	}

	public void runBeforesThenTestThenAfters(Runnable test) {
		try {
			runBefores();
			test.run();
		} catch (FailedBefore e) {
		} catch (Exception e) {
			throw new RuntimeException("test should never throw an exception to this level");
		} finally {
			runAfters();
		}		
	}
	
	protected void runTestMethod() {
		try {
			fTestMethod.invoke(fTest);
			if (fTestMethod.expectsException())
				addFailure(new AssertionError("Expected exception: " + fTestMethod.getExpectedException().getName()));
		} catch (InvocationTargetException e) {
			Throwable actual= e.getTargetException();
			if (actual instanceof AssumptionViolatedException)
				return;
			else if (!fTestMethod.expectsException())
				addFailure(actual);
			else if (fTestMethod.isUnexpected(actual)) {
				String message= "Unexpected exception, expected<" + fTestMethod.getExpectedException().getName() + "> but was<"
					+ actual.getClass().getName() + ">";
				addFailure(new Exception(message, actual));
			}
		} catch (Throwable e) {
			addFailure(e);
		}
	}

下面是使用spring-test的runner如何来写testcase, 将会有不少简化(推荐懒人使用):
要测试的方法:
public class ExampleObject {

	public boolean getSomethingTrue() {
		return true;
	}

	public boolean getSomethingFalse() {
		return false;
	}
}

测试用例:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/applicationContext.xml" })
public class ExampleTest {
	@Autowired
	ExampleObject objectUnderTest;

	@Test
	public void testSomethingTrue() {
		Assert.assertNotNull(objectUnderTest);
		Assert.assertTrue(objectUnderTest.getSomethingTrue());
	}

	@Test
	@Ignore
	public void testSomethingElse() {
		Assert.assertNotNull(objectUnderTest);
		Assert.assertTrue(objectUnderTest.getSomethingFalse());
	}
}

xml配置:
<?xml version="1.0" encoding="gb2312"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean id="objectUnderTest" class="com.taobao.demo.spring.test.ExampleObject">
    </bean>
</beans>

如果是使用maven的话, pom.xml的配置:
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.4</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>2.5.5</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>2.5.4</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>2.5.4</version>
		</dependency>
	</dependencies>

6
0
分享到:
评论
2 楼 skyuck 2011-03-25  
学习了,楼主整理的很好
1 楼 xly_971223 2009-04-23  
楼主整理的非常好
只是版本太老了

junit4.6已经废弃了JUnit4ClassRunner类

好多的方法名字都变了

相关推荐

    浅析webwork

    【标题】:“浅析WebWork” 【正文】: WebWork是一个历史悠久的Java Web应用程序框架,它在早期的Web开发中扮演了重要的角色,为开发者提供了强大的MVC(模型-视图-控制器)架构支持。本篇文章将深入探讨WebWork...

    浅析Jenkins在java项目开发中的应用.zip

    ### 4. 自动化测试 Jenkins可以集成JUnit、TestNG等测试框架,自动执行单元测试和集成测试。测试结果会以可视化的方式展示,帮助开发者快速定位问题。此外,Jenkins还支持SonarQube集成,进行代码质量分析和静态...

    play1的文档资料

    此外,Play框架支持多种数据库,如H2、MySQL等,并且集成了JUnit进行单元测试。 2. **Play框架的Hotswap功能** Hotswap功能是Play的一个亮点,它允许开发者在运行时修改代码并立即看到效果,无需重新启动服务器。...

    统考计算机应用基础考试大纲(2013年修订版).doc

    统考计算机应用基础考试大纲(2013年修订版).doc

    基于机器学习的区域现代化水平指数分析

    内容概要:本文基于机器学习方法,探讨了中国区域现代化水平及其对经济效益的影响。研究首先构建了现代化发展评价指标体系,涵盖了经济、科技、人文、社会和文化五个维度,并采用突变级数法和熵权法计算出组合期望值。接着,利用BP神经网络模型对区域现代化水平指数进行拟合,结果显示我国现代化水平存在显著的区域差异,呈现东部沿海地区较高、西部内陆地区较低的特征。最后,通过随机森林模型分析发现,经济现代化和科技创新现代化是影响GDP最重要的两个因素,文化现代化次之,而人文和社会现代化的影响相对较小。;

    电机控制领域本杰明磁链模型的闭环带载启动与代码优化实践

    内容概要:本文详细介绍了本杰明磁链模型在电机控制领域的应用,特别是在闭环带载启动方面的优势。文章首先展示了磁链模型的核心参数初始化及其精确性要求,接着深入探讨了磁链观测器的设计与实现,包括其微分方程、积分器以及遗忘因子的作用。文中还讨论了代码生成过程中遇到的问题及解决方案,如MATLAB生成代码的效率优化和查表法的应用。此外,文章介绍了带载启动的具体策略,包括转速-电流双闭环嵌套控制和滑模控制器的应用,并分享了实际测试数据和效果。最后,文章提供了调试经验和实战案例,强调了模型的鲁棒性和实用性。 适合人群:从事电机控制系统设计与开发的工程师和技术人员,尤其是关注高性能带载启动解决方案的专业人士。 使用场景及目标:适用于需要提高电机启动可靠性和稳定性的应用场景,如工业自动化设备、物流AGV等。目标是通过引入本杰明磁链模型,实现高效稳定的带载启动,减少启动时的电流波动和机械振动。 其他说明:本文不仅提供了理论分析,还包括大量实际代码示例和调试技巧,帮助读者更好地理解和应用这一先进技术。

    三电平NPC有源电力滤波器无差拍控制的MATLAB仿真与实现

    内容概要:本文详细介绍了三电平NPC(Neutral Point Clamped)有源电力滤波器(APF)采用无差拍控制方法的MATLAB仿真过程。首先阐述了三电平NPC拓扑的优势及其在高压大功率场景的应用背景,接着深入探讨了无差拍控制的核心数学模型,包括电流预测、调制环节以及中点电位平衡处理。文中还提供了具体的MATLAB代码片段,展示了如何实现电流误差的前馈补偿、三电平PWM生成、SVPWM矢量切换逻辑等关键技术。此外,文章强调了仿真过程中需要注意的关键参数设置,如采样时间、电感值、调制策略等,并分享了一些常见的调试技巧和潜在问题的解决方案。 适用人群:从事电力电子、电力系统自动化领域的研究人员和技术人员,尤其适用于对有源电力滤波器和无差拍控制感兴趣的工程师。 使用场景及目标:①理解和掌握三电平NPC APF的工作原理和无差拍控制策略;②利用MATLAB/Simulink进行相关仿真的设计与调试;③提高谐波补偿效果,降低THD(总谐波失真),提升系统的动态响应性能。 其他说明:文章不仅提供了详细的理论分析和代码实现,还分享了许多实践经验,帮助读者更好地应对实际应用中的挑战。同时,提醒读者注意仿真环境与实际情况之间的差异,确保最终设计方案的可行性和可靠性。

    HBase 是一个基于 Hadoop 的分布式、面向列的 NoSQL 数据库,适用于海量数据存储与实时读写

    hbase的安装与简单操作

    基于COMSOL仿真的变压器三相短路绕组振动及电磁力分析

    内容概要:本文详细介绍了使用COMSOL软件进行变压器三相短路工况下绕组振动及电磁力的仿真分析。首先,通过定义绕组几何参数和材料属性,构建了电磁场和固体力学的多物理场耦合模型。然后,利用参数化扫描和频域电磁分析方法,精确模拟了短路瞬间的电磁场分布、轴向力、径向力以及磁密分布情况。接下来,在固体力学模块中引入瑞利阻尼和初始应力设置,实现了对绕组振动特性的动态仿真。最后,通过对仿真结果的后处理,得到了振动位移、力分布和频谱分析等重要数据,揭示了短路工况下绕组的复杂力学行为及其优化方向。 适合人群:从事电力设备设计、电磁兼容性和结构动力学研究的专业技术人员,尤其是有一定COMSOL仿真经验的研究人员。 使用场景及目标:适用于变压器设计过程中评估短路工况对绕组的影响,帮助工程师理解并解决因短路引起的振动和应力问题,从而提高变压器的安全性和可靠性。 其他说明:文中提供了详细的建模步骤和技术细节,强调了正确选择坐标系、材料参数和阻尼设置的重要性,并分享了一些避免常见错误的经验。

    CATIA DMU中麦弗逊悬架与齿轮齿条转向系统的非参数化运动仿真及应用

    内容概要:本文详细介绍了如何在CATIA DMU模块中进行麦弗逊式独立悬架与齿轮齿条转向器的非参数化运动仿真。首先,文章解释了底盘结构及其运动特性,接着逐步展示了如何设置悬架和转向系统的运动副,包括旋转副、滑动副以及齿轮齿条副的具体配置方法。文中还特别强调了仿真过程中需要注意的技术细节,如参数设置、摩擦系数的选择、运动自由度的限制等。此外,作者分享了一些实用技巧,比如通过正弦函数驱动转向输入、利用传感器监测运动状态、导出并修改仿真动画等。 适合人群:从事汽车工程设计、机械仿真的工程师和技术人员,尤其是熟悉CATIA软件的用户。 使用场景及目标:适用于需要进行车辆转向系统和悬架系统联合仿真的场合,帮助工程师更好地理解和优化车辆动态性能,提高设计效率。 其他说明:文章提供了大量具体的VBA代码片段,便于读者直接应用于自己的项目中。同时,文中提到的一些调试经验和常见问题解决方法也非常有价值。

    蓝色企业CMS网站后台管理模板

    蓝色企业CMS网站后台管理模板

    HBase 的安装与简单操作教程

    HBase 是基于 Java 开发的,需要安装 Java 8 或更高版本。可以通过在命令行中输入java -version来检查 Java 版本,如果未安装则需先安装 Java。HBase 依赖于 Hadoop 的分布式文件系统(HDFS)来存储数据,需要先安装并配置好 Hadoop 集群。确保 Hadoop 的相关服务(如 HDFS、YARN 等)已经正常启动。

    电力电子领域PQ控制三相并网逆变器的PWM调制、LCL滤波及电流THD优化

    内容概要:本文深入探讨了PQ控制三相并网逆变器的技术细节,涵盖PWM调制策略、LCL滤波器设计及其对电流THD的影响。PWM调制策略通过SPWM和SHEPWM实现直流电压到交流电压的高效转换;PQ控制方法利用电网电压定向的矢量控制原理,精确调节有功和无功功率;LCL滤波器有效抑制高频谐波,确保电流THD达到2.6%。此外,文中还介绍了仿真模型的搭建和调试技巧,展示了各模块之间的协同工作。 适合人群:从事电力电子研究和技术开发的专业人士,尤其是关注并网逆变器设计和优化的研究人员和工程师。 使用场景及目标:适用于希望深入了解并网逆变器内部机制的研发人员,帮助他们在实际工程项目中提高逆变器性能,降低谐波失真,优化系统效率。 其他说明:文中提供的代码片段和仿真模型有助于读者更好地理解和实践相关技术,同时引用了多篇权威文献供进一步学习。

    多智能体系统MATLAB仿真:间歇控制下的离散编队控制及其第二分量动态分析

    内容概要:本文探讨了多智能体系统在间歇控制下的离散编队控制,特别是在MATLAB仿真环境中实现的具体方法和技术细节。文章首先介绍了多智能体系统的基本概念和背景,随后详细解释了间歇控制的概念及其在离散系统中的应用。文中提供了具体的MATLAB代码示例,用于演示智能体间的通信拓扑、控制策略以及状态更新过程。此外,还讨论了仿真过程中遇到的问题,如控制间隔的选择、耦合强度的影响等,并给出了相应的解决方案。最后,文章通过分析第二分量的仿真图,展示了间歇控制的有效性和特点。 适合人群:对多智能体系统、控制理论、MATLAB仿真感兴趣的科研人员、研究生及工程技术人员。 使用场景及目标:适用于研究多智能体系统的一致性、编队控制、包含控制等问题,旨在通过MATLAB仿真平台,理解和掌握间歇控制在离散系统中的应用,提高对智能体系统动态行为的认识。 其他说明:文章不仅提供了详细的代码实现,还分享了许多实践经验,如避免使用连续求解器、选择合适的控制参数等,有助于读者更好地进行实验和研究。同时,文章鼓励读者尝试不同的控制策略和参数设置,以探索更多的可能性。

    基于MATLAB的西班牙风电场风速与功率预测模型:CEEMDAN分解与花授粉优化算法的应用

    内容概要:本文详细介绍了利用MATLAB进行西班牙风电场风速与功率预测的完整流程。首先,通过CEEMDAN分解将原始风速信号分解为多个本征模态分量(IMF),并处理残差项。接着,使用花授粉算法(FPA)优化极限学习机(ELM)和BP神经网络的权重,提高预测精度。针对风速-功率曲线的非线性特点,引入分段校正层进行功率预测。文中提供了详细的代码示例和参数设置建议,强调了数据预处理、模型优化和结果分析的关键步骤。 适合人群:从事风电场数据分析、预测建模的研究人员和技术人员,以及对MATLAB编程有一定基础的学习者。 使用场景及目标:适用于需要对复杂地形条件下的风电场进行精确风速和功率预测的场景。主要目标是通过先进的信号分解和优化算法,提高预测模型的准确性,减少预测误差。 其他说明:文中提到的技术手段不仅限于西班牙风电场,对于其他地区类似应用场景也有很好的借鉴意义。建议使用者根据具体数据情况进行适当调整,如IMF数量的选择、FPA参数的设定等。

    等离子体仿真中Ar细通道棒板流注放电的电子密度与温度分析及应用

    内容概要:本文详细介绍了使用Comsol软件对Ar细通道棒板流注放电进行仿真的方法和技术细节。主要内容涵盖了几何模型的建立、物理场的设置、求解器的配置以及电子密度和电子温度的仿真结果分析。文中强调了在仿真过程中需要注意的关键参数和技巧,如网格划分、初始条件的选择、边界条件的设置等。通过对仿真结果的深入探讨,揭示了电子密度和电子温度在流注放电过程中的时空变化规律及其背后的原因。 适合人群:从事等离子体物理学研究的专业人士、研究生及以上学历的研究人员。 使用场景及目标:适用于需要深入了解Ar细通道棒板流注放电特性的科研项目,旨在帮助研究人员掌握Comsol仿真工具的应用技巧,提高仿真精度和效率。 其他说明:文章不仅提供了详细的仿真步骤指导,还分享了许多实践经验,有助于解决仿真过程中常见的问题。此外,文章还提到了一些优化求解器性能的方法,如采用分段扫描、分离求解等策略,进一步提升了仿真的实用性。

    Android平台高通相机camera CamX架构的awbwrapper node算法设计

    Android平台高通相机camera CamX架构的awbwrapper node算法设计

    DC-DC斩波电路中BUCK与BOOST电路的高压降压及低压升压设计与仿真

    内容概要:本文详细探讨了DC-DC斩波电路中BUCK(降压)和BOOST(升压)两种电路的设计与仿真。对于BUCK电路,重点讨论了将200V降至50V的具体实现方法,包括占空比计算、电感选型以及开关损耗等问题,并提供了Python代码进行动态仿真。对于BOOST电路,则介绍了将6V升至15V的操作原理,涉及占空比设置、PWM控制及其Arduino代码实现。此外,还强调了实际应用中的注意事项,如电感电流纹波、二极管选择、MOSFET驱动隔离等。 适合人群:从事电力电子、嵌入式系统开发的技术人员,尤其是对DC-DC转换器有一定了解的研究者或工程师。 使用场景及目标:适用于需要深入了解BUCK和BOOST电路工作原理及其具体应用场景的人群。目标是帮助读者掌握这两种电路的设计要点,能够独立完成相关电路的设计与调试。 其他说明:文中不仅提供了理论推导和公式计算,还有具体的代码实例用于辅助理解和验证。同时,分享了一些实用的小贴士,有助于解决实际项目中遇到的问题。

    基于遗传算法的风电混合储能系统容量优化配置(MATLAB实现)

    内容概要:本文详细介绍了如何利用遗传算法对风电场的混合储能系统进行容量优化配置。首先解释了混合储能系统的基本结构及其重要性,然后逐步展示了如何用MATLAB实现遗传算法的关键步骤,包括种群初始化、适应度函数设计、交叉变异操作以及参数调优。文中还提供了具体的代码片段和实例,如初始化函数、适应度函数、交叉变异操作等,并通过实际案例验证了算法的有效性。此外,文章强调了遗传算法在处理复杂非线性问题时的优势,并给出了若干实用建议和技术细节。 适合人群:从事风电储能系统研究与开发的技术人员、研究生及以上学历的相关专业学生。 使用场景及目标:适用于需要对风电场储能系统进行优化配置的研究和工程项目,旨在降低成本、提高系统稳定性和经济效益。 其他说明:文中提供的代码可以直接用于MATLAB环境运行,同时附有详细的注释帮助理解。针对不同应用场景,可以根据实际情况调整参数和约束条件。

    混合动力汽车P2构型SIMULINK整车模型构建与仿真

    内容概要:本文详细介绍了并联P2构型的智混合动力汽车在SIMULINK平台上的整车模型搭建及其仿真过程。文章首先解释了P2构型的特点,即电动机位于发动机和变速箱之间,能够实现纯电驱动以及发动机和电动机共同工作的灵活性。接着阐述了如何利用MATLAB/SIMULINK创建包含发动机、电动机、电池等多个模块在内的整车模型,并展示了部分用于初始化各组件参数的基础代码片段。随后讨论了基于规则的控制策略,包括不同行驶条件下动力源的选择逻辑,如车速较低且电池电量足够时采用纯电模式,反之则启用混合动力模式。此外,文中还涉及到了具体的仿真步骤,强调了对仿真结果的关注,特别是发动机转速、电动机功率、电池电量的变化趋势。最终,作者分享了一些优化技巧,例如调整扭矩分配算法、修正单位转换错误等,使得模型更加贴近实际情况。 适合人群:从事新能源汽车研发的技术人员,尤其是熟悉MATLAB/SIMULINK工具链的研究者。 使用场景及目标:适用于希望深入了解混合动力汽车内部运作机制的人群,旨在帮助他们掌握从理论到实践的具体流程,从而为实际项目提供参考。 其他说明:文中提供了大量实用的代码示例和技术细节,有助于读者快速入门并深入理解相关知识点。同时,通过对模型验证环节的描述,突出了工程实践中遇到的问题及解决方案。

Global site tag (gtag.js) - Google Analytics