快捷搜索:  as  test  1111  test aNd 8=8  test++aNd+8=8  as++aNd+8=8  as aNd 8=8

和记娱h188下载app手机版_集报网



实际 Java 开拓中单元测试常碰到的问题

在敏捷开拓中,为了前进软件开拓的效率和质量,测试驱动开拓实践已经被广泛应用。在测试驱动开拓的项目中,跟着项目开拓赓续地深入,积累的测试用例会越来越多。测试驱动开拓的一个最佳实践是随时运行测试用例,包管任何时刻测试用例都能成功履行,从而包管项目的代码是可事情的。当测试用例数量很多时,一次运行所有测试用例所耗损的光阴可能会很长,导致运行测试用例的资源很高。以是在实际敏捷开拓中,若何组织、运行测试用例以匆匆进测试驱动开拓成为一个值得商量的问题。

JUnit 是 Java 开拓中最常用的单元测试对象。在 JUnit3 用 TestSuite 来显式地组织想要运行的 TestCase,平日 TestSuite 的组织大年夜体上和 Java Package/Class 的组织类似,但这样并不能和当前正在实现的营业需求完全相关,显得对照愚蠢,比如说要运行某个子模块下所有的 TestCase,或者运行跟某个详细功能相关的 TestCase,涉及到的 TestCase 数量可能较多,采纳定义 TestSuite 的要领一个个地添加 TestCase 很低效并且繁琐。在 JUnit4 中同样只能显式地组织要运行的 TestCase。

怎么样办理这些问题,新宣布的 JUnit4 供给了开拓职员扩展的机制,可以经由过程对 JUnit 进行扩展来供给一种办理的措施。

JUnit4 的新特点和扩展机制

JUnit4 引入了 Java5 的 Annotation 机制,来简化原有的应用措施。测试用例不再必要承袭 TestCase 类,TestSuite 类也取消了,改用 @Suite.SuiteClasses 来组织 TestCase。然则这种照样经由过程显示指定 TestCase 来组织运行的布局,不能办理上述的问题。关于 JUnit4 的新特点详细可以参考 developerworks 的文章。

JUnit4 的实今世码中供给了 Runner 类来封装测试用例的履行。它本身供给了 Runner 的多种实现,比如 ParentRunner 类、Suite 类,BlockJUnit4ClassRunner 类。我们可以充分使用 JUnit4 供给的已有举措措施来对它进行扩展,实现我们期望的功能。

首先我们来阐发一下 JUnit4 在运行一个测试用例时,它内部的核心类是若何事情的。图 1 展示了 JUnit4 运行测试用例时,核心类之间的调用关系。

图 1. JUnit4 核心类之间的调用关系

在 JUnit4 中,Runner 类定义了运行测试用例的接口,默认供给的 Runner 实现类有 Suite、BlockJUnit4ClassRunner、Parameterized 等等。Suite 类相称于 JUnit3 中的 TestSuite,BlockJUnit4ClassRunner 用和记娱h188下载app手机版来履行单个的测试用例。BlockJUnit4ClassRunner 关联了一个 TestClass 类,TestClass 封装了测试用例的 Class 元数据,可以造访到测试用例的 method、annotation 等。FrameworkMethod 封装了测试用例措施的元数据。从下图中我们可以看到这些类的关系。

图 2. JUnit4 核心类

经由过程扩展 JUnit4,我们一方面可以无缝地使用 JUnit4 履行测试用例的能力,另一方面可以将我们定义的一些营业功能添加到 JUnit 中来。我们将自定义一套与运行测试用例相关的营业属性的 Annotation 库,定义自己的过滤器,扩展 JUnit 类的 Runner,从而实现定制化的测试用例的履行。

JUnit4 扩展的实现

下面我们来描述一下对 JUnit4 扩展的实现。扩展包括 4 个模块,Annotation 定义、用户查询前提封装、过滤器定义、核心类定义。

JUnit4 用 Annotation 来定义测试用例运行时的属性。我们可以定义自己的 Annotation 库。经由过程定义出详细项目中和履行测试用例相关的属性元数据, 比如某个模块,某个特点,将这些属性经由过程 Annotation 附加到测试用例中,在扩展的 R和记娱h188下载app手机版unner 中使用过滤器对测试用例进行过滤,从而履行目标测试用例。

根据实际项目中的开拓履历,我们大年夜体抽象出了如下的几种 Annotation, 可以映射到我们项目的营业功能划分上;

表 1. 扩展的 Annotation 的详细用法

名称

参数

感化域

Product

字符串参数,指定要测试的产品项目名称

Release

字符串参数,指定详细的 Release 编号

类、措施

Component

字符串参数,指定子模块、子系统

Feature

字符串参数,指定某个详细的功能、需求

类、措施

Defect

字符串参数,指定测试中发明的 Defect 的编号

类、措施

UseCaseID

字符串参数,指定 UseCase 的编号

类、措施

当我们想要运行所有和 Feature 相关的测试用例时,我们只要指定履行前提,就可以只运行那部分测试用例,而不会去运行整个的测试用例。这种措施从营业的角度来看,加倍具有针对性,而且简洁快速,比用传统的经由过程 TestSuite 指定测试用例的要领加倍得当测试驱动开拓的场景。下面给出 Feature Annotation 和 Release Annotation 的定义作为示例。

清单 1:Feature Annotation 的定义

@Target({ElementType.TYPE, ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

public @interface Feature {

String value();

}

清单 2:Release Annotation 的定义

@Target({ElementType.TYPE, ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

public @interface Release {

String value();

}

接下来是封装用户输入的履行前提。在这里我们约定用户输入的履行前提的款式是:“前提 A = 值 A,前提 B = 值 B”。比如用户想履行 Release A 中的跟 Feature B 相关的测试用例和措施,那么用户的输入前提可以定义为“Release=A,Feature=B”。下图是封装用户输入的类的布局:

图 3. 封装用户输入的履行前提的类

过滤器是用来根据用户输入,对目标测试用例和测试措施进行过滤,从而找到相符前提的测试用例措施。用户输入的每个前提都邑生出响应的一个过滤器,只有测试用例满意过滤器链中所有的过滤前提,测试用例才能被履行。下面的清单展示了过滤器接口的定义和过滤器工厂的核心实现。过滤器工厂会根据用户输入的前提来创建对应的过滤器。

清单 3 . Filter 接口的定义

public interface Filter {

public bool和记娱h188下载app手机版ean shouldRun(IntentionObject object);

}

清单 4 . FilterFactory 的部分实现

public class FilterFactory {

public static Map, List> createFilters(String intention)

throws ClassNotFoundException{

Map, List> filters = new HashMap, List>();

String[] splits = intention.split(ExtensionConstant.REGEX_COMMA);

for(String split : splits){

String[] pair = split.split(ExtensionConstant.REGEX_EQUAL);

if(pair != null && pair.length == 2){

Filter filter = createFilter(pair[0],pair[1]);

String annotationType = ExtensionConstant.ANNOTATION_PREFIX + pair[0];

Class annotation = Class.forName(annotationType);

List filterList = null;

if(filters.containsKey(annotation)){

filterList = filters.get(annotation);

}else{

filterList = new ArrayList();

}

filterList.add(filter);

filters.put(annotation, filterList);

}

}

return filters;

}

………………

}

核心类模块和记娱h188下载app手机版中的类是对 JUnit4 中的类的扩展,从下图中可以看到两者的承袭关系:

图 4. 核心扩展类和 JUnit4 中类的承袭关系

Request 类是 JUnit4 顶用来表示一次测试用例哀求的抽象观点。它是一次测试用例履行的发动身点。RunerBuilder 会根据测试用例来创建响应的 Runner 实现类。BlockJUnit4ClassRunner 是 JUnit4 顶用来履行零丁一个测试用例的 Runner 实现类。我们经由过程扩展它,来得到 JUnit 履行测试用例的能力,同时在 ExtensionRunner 中调用过滤器对测试用例措施进行过滤,从而根据我们定义的营业规则来履行测试用例。Result 类是 JUnit4 顶用来封装测试用例履行结果的类,我们对它进行了扩展,来款式化测试用例履行结果的输出。下面给出 ExtensionRunner 的部分实现。

清单 5. ExtensionRunner 部分实现

public class ExtensionRunner extends BlockJUnit4ClassRunner {

private Map, List> filtersForAnnotation;

public ExtensionRunner(Class klass, String intention)

throws InitializationError, ClassNotFoundException {

super(klass);

filtersForAnnotation = FilterFactory.createFilters(intention);

}

protected Statement childrenInvoker(final RunNotifier notifier) {

return new Statement() {

@Override

public void evaluate() {

runChildren(notifier);

}

};

}

protected void runChildren(final RunNotifier notifier) {

for (final FrameworkMethod each : getFilteredChildren()) {

runChild(each, notifier);

}

}

protected List getFilteredChildren() {

ArrayList filtered = new ArrayList();

for (FrameworkMethod each : getChildren()) {

if (shouldRun(each)) {

filtered.add(each);

}

}

return filtered;

}

protected boolean shouldRun(FrameworkMethod method) {

List result = new ArrayList();

Annotation[] classAnnotations = method.getAnnotations();

Map,Annotation> methodAnnotationMap =

getAnnotaionTypeMap(classAnnotations);

Set> annotationKeys = filtersForAnnotation.keySet();

for(Class annotationKey : annotationKeys ){

if(methodAnnotationMap.containsKey(annotationKey)){

List filters = filtersForAnnotation.get(annotat和记娱h188下载app手机版ionKey);

if (filters != null) {

for (Filter filter : filters) {

if (filter != null

&& filter.shouldRun(

IntentionFactory.createIntentionObject(

methodAnnotationMap.get(annotationKey)))) {

result.add(true);

}else{

result.add(false);

}

}

}

}else{

return false;

}

}

if(result.contains(false)){

return false;

}else{

return true;

}

……………………

}

}

经由过程测试用例实例展示 JUnit 扩展的履行效果

1)创建一个 Java 项目,添加对 JUnit4 扩展的引用。项目的布局如下:

图 5. JUnit4 扩展示例法度榜样的项目布局

2)创建一个简单的待测试类 Demo 类。

清单 6. 待测试类

public class Demo {

public int add(int a, int b){

return a + b;

}

public int minus(int a, int b){

return a - b;

}

}

3)创建一个 JUnit4 风格的测试用例 DemoTest 类,对上述 Demo 类的措施编写测试,并将我们自定义的 Annotation 元数据嵌入到 DemoTest 的测试措施中。

清单 7. 包孕了自定义 Annotation 的测试用例

public class DemoTest {

@Test

@Feature("Test Add Feature")

@Release("9.9")

public void testAdd() {

Demo d = new Demo();

Assert.assertEquals(4, d.add(1, 2));

}

@Test

@Release("9.9")

public void testMinus() {

Demo d = new Demo();

Assert.assertEquals(2, d.minus(2, 1));

}

}

4)编写 Main 类来履行测试用例,输入自定义的履行测试用例的前提“Release=9.9,Feature=Test Add Feature”,来履行 9.9 Release 中跟 Add Feature 相关的测试用例措施,而不履行跟 Minus Feature 相关的测试用例措施。

清单 8. 调用 JUnit4 扩展来履行测试用例

public class Main {

public static void main(String... args){

new JUnitExtensionCore().runMain(args);

}

}

图 6. 自定义履行测试用例的前提

5) 履行结果:testAdd() 措施满意履行的前提,它履行了。testMinus() 措施不满意履行前提,它没有履行。

图 7. 测试用例履行结果

6)改变自定义的履行前提为“Release=9.9”,履行跟 9.9 Release 相关的所有测试用例措施。

图 8. 自定义履行测试用例的前提

7) 履行结果:testAdd() 措施和 testMinus() 措施都满意履行前提,都履行了。

图 9. 测试用例履行结果

结论

经由过程上述的代码示例我们可以看出,我们经由过程对 JUnit4 进行扩展,从而可以自定义测试用例履行的前提,将测试用例的履行和详细的营业功能结合在一路,快速地根据营业功能来履行响应的测试用例。这种细粒度的,以营业属性来组织测试用例的措施,加倍得当以测试用例为本的测试驱动开拓的需求。可以实现快速地运行目标测试用例,从而匆匆进测试驱动开拓在项目中更好地实践。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

您可能还会对下面的文章感兴趣: