AX 演示:使用单元测试框架测试类

原文:http://msdn.microsoft.com/en-us/library/bb410465.aspx

演示:使用单元测试框架测试类

AX集成了一个单元测试框架,该框架用于创建、运行及分析单元测试。在这个演示中,你将创建一个满足特定要求的Employee类,创建一个测试用例来测试类是否满足了这些要求。单元测试框架基于TDD(测试驱动开发)。关于TDD的更多信息,请查看测试驱动开发向导TDD建议首先创建测试用例(这个时候由于没有写被测试的类的代码,所以测试用例运行会失败),然后创建类并书写代码以满足类的要求,并可以通过测试。下面的步骤提及了TDD过程,但目的是强调单元测试框架。在你创建和运行测试用例后,你可以查看代码覆盖率,为测试用例设置隔离等级。

Employee需要符合以下要求:

  • 但一个Employee类的实例被创建时,类的名字使用方法name来设置。
  • Employee类有一个retire方法,在职员退休时调用retire。对于同一职员该方法只能被调用一次。

这一演示将阐述以下任务:

  • 创建一个Employee类根(指只包含类声明没有任何方法和实现的类)
  • 创建一个测试类
  • 为测试用例设置数据
  • name方法这一要求创建一个测试用例
  • 运行测试用例retire方法这一要求创建一个测试用例
  • 步骤代码覆盖率
  • 设置隔离等级

先决条件


完成这一演示,你需要:

  • Microsoft Dynamics AX
  • 拥有包含开发权限的License

创建Employee类根


遵循TDD的原则,在写任何类的实现以前首先创建测试用例。为了减少编译错误,你需要先创建一个类根(class stub),只有一个类什么,没有任何实现。

创建Employee

1. 打开Microsoft Dynamics AX

2. CTRL+D打开应用程序对象树(AOT)。3. AOT上,右键单击Classes节点,然后点击‘New class’

注释

Classes节点扩展出一个新的命名为Class1的类。

4. 右键单击Class1,点击Rename然后重新命名为Employee

创建测试类


创建测试用例的时候,你需要创建一个类,其命名必须符合最佳实践以关联到被测试的类。测试类的名字为被测试类的名字加Test。在这一步骤里,你将创建一个继承自SysTestCase的子类EmployeeTest

创建测试类

1. 右键单击Classes节点,然后点击New class

2. 双击Class1打开代码编辑器。3. 在代码编辑器中,通过修改声明继承SysTestCase。并声明一个Employee类的实例。

class EmployeeTest extends SysTestCase

{

// Create a member variable named employee.

Employee employee;

}

为测试用例设置数据


在这一步骤中,你将创建一个Employee类的实例,它将被用在所以测试用例中。

为测试用例设置数据

1. AOT中,右键单击EmployeeTest,选择Override method,然后点击Setup

2. 在代码编辑器中,按如下代码修改setUp方法。

public void setUp()

{

;

// Create an employee instance to use in test cases.

employee = new Employee("your name");

super();

}

Name方法这一要求添加测试用例


在这一步骤中,你将添加一个测试用例。你将为类EmployeeTest添加一个新的方法,严重epmployeename被正确设置。

name要求添加测试用例

EmployeeTest类,选择New method

2. 在代码编辑器中,按如下代码修改该方法。

void testName()

{

// Verify that the employee name is set correctly.

this.assertEquals("your name",employee.name());

}

现在如果运行这个测试用例会是失败的,你可以为这一测试用例书写特征代码以完成编译并可以使测试用例运行成功。并重写Employee类的new方法以接受一个字符串作为参数。

添加特征代码

AOT上,在classDeclaration方法节点上右键双击。

2. 在代码编辑器中,按如下代码修改声明。

class Employee

{

// Create member variables.

str name;

}

Employee 类节点,选择new4. 在代码编辑器中,按如下代码修改new方法。

void new(str _name)

{

;

name = _name;

}

5. Employee类,点击6. 在代码编辑器中,按如下代码修改该方法。

public str name()

{

;

// Return the expected string.

return name;

}

7. Employee类并点击Compile8. 右键单击Compile

运行测试用例


在这一步骤中,你将通过单元测试工具栏来运行测试用例。运行测试用例的更多信息请查看:如何运行测试用例

运行测试用例

  • AOT上,右键单击EmployeeTest类,选择Add-Ins,然后点击Run tests

注释

将会打开单元测试工具栏并且运行测试。由于只添加了一个测试用例,所以运行结果是‘1 run,0 failed’。

在这一步骤中,你将修改测试用例以使测试失败。在TDD中,首先都是创建一个运行失败的测试用例。由于编译的原因,在这个例子中,首先便创建了运行会成功的测试用例。

使测试用例失败

AOT上,双击Employee 类的name方法节点。In the AOT,in the Employee class node,double-click the name method.

public str name()

{

;

// Return the expected string.

// return name;

// Return an empty string to make the test case fail.

return "";

}

4. 在单元测试工具栏上,点击Run按钮。

运行结果显示‘’。Infolog显示预期的结果和实际的结果。

Error:

[EmployeeTest.testName]Failure: Assertion failed! (Expected: your name; Actual: )

Infolog中,可以点击Edit按钮打开代码编辑器并定位到断言失败的地方。6. name方法。7. 在代码编辑器中,按如下代码修改该方法。

public str name()

{

// Return the expected string.

return name;

// Return an empty string to make the test case fail.

// return "";

}

8. Employee类,并点击

Retire需求添加测试用例


在这一步骤中,你将为退休这一需求创建测试用例。你将给EmployeeTest添加一个新的方法来完成这一测试用例。这样测试用例用于验证对应同一职员,如果retire方法被调用超过一次,将会抛出异常。同样,遵循TDD的原则,你将在写任何被测试类的实现前首先创建测试用例,所以不要编译。

为退休这一需求添加测试用例

EmployeeTest然后点击

void testRetire()

{

;

// Call the retire method,first time should be successful.

employee.retire();

// Expect an exception to be thrown because the employee is

// already retired.

this.parmExceptionExpected(true,"Already retired");

employee.retire();

}

在你为Employee类添加retire方法前,不要编译测试用例。你必须为Employee类添加一个变量才存储职员是否已退休。为了简化这个例子,你将抛出一个静态字符串的错误信息,在实际使用时,你应该创建一个label而不是使用静态文本‘Already retired’。

添加retire方法

classDeclaration方法上双击。

2. 在代码编辑器中,为ClassDeclaration方法添加如下成员变量。

boolean retired;

4. 在代码编辑器中,按如下代码修改该方法。

public void retire()

{

// If retired,throw an exception,otherwise set the retired value to true.

if (retired)

throw error("Already retired");

retired = true;

}

Employee类点击6. 右键单击EmployeeTest类,点击7. 在单元测试工具栏上,点击

由于添加了两个测试用例,所以运行结果显示‘2 run,0 failed’。你可以通过不第二次调用testRetire方法来是第二个测试用例运行失败。按如下代码修改:

void testRetire()

{

;

// Call the retire method,first time should be successful.

employee.retire();

// Expect an exception to thrown because the employee is already retired.

this.parmExceptionExpected(true,"Already retired");

// employee.retire();

}

捕捉代码覆盖率


你必须修改调试参数以使运行捕捉代码覆盖率。在这一步骤中,你将设置调试模式为When breakpoint。你也将看到单元测试框架提供的各种查看运行结果的Form

设置调试模式并显示测试用例运行结果

1. 点击Tools/Options

2. Options表中,点击Development标签页。Development标签页中,选择Debug组,点击Debug mode字段的下拉按钮,选择When breakpoint4. AX的系统按钮中,点击Tools/Development tools/Unit test/Parameters5. 在单元测试属性表中,在General标签页,勾选Record code coverage选项框。默认情况下,Database被作为记录代码覆盖率的监听器。6. 关闭所有Form和报表。7. 在单元测试工具栏上点击8. 点击单元测试工具栏的Details按钮。

你可以看到EmployeeTest测试用例被运行。详细信息显示测试用例运行的时间、日期、被谁运行、代码覆盖率及运行结果。

9. 点击General标签页。

你将看到以毫秒为单位的EmployeeTest测试用例运行所耗时间。10. 点击Environment标签页。

你将看到EmployeeTest测试用例运行的系统环境。11. 点击Tests按钮。

Test form的下边的窗格,可以看到方法级别的统计信息。你可以看到每一个方法的代码覆盖率。

设置隔离级别


根据测试用例对数据操作的不同需要设置不同的隔离级别。单元测试框架提供了4种测试套件分别提供不同的隔离级别。更多的信息,请查看单元测试框架。在这一步骤中,你将重写createSuite方法以使用SysTestSuiteCompanyIsolateClass测试套件。这一测试套件为每一个测试类创建新的空的公司账号名,每一个测试方法都在该公司下运行。

设置测试用例的隔离级别

createSuite

2. 在代码编辑器中,在代码行 ret = super();中选择super,右键单击点击Lookup definitionNote

默认情况下,基类的createSuite方法返回SysTestSuite测试套件,它不提供任何隔离级别。

3. 关闭基类createSuite方法所在代码编辑器。EmployeeTest类的createSuite方法。

public SysTestSuite createSuite()

{

// Specify the isolation level that constructs an empty company account for the entire test class and then deletes when complete.

return new SysTestSuiteCompanyIsolateClass(this);

}

6. 点击单元测试工具栏的

在第一次运行测试后,所有表会被循环遍历并删除。但第二次运行测试用例时,测试用例的运行速度会比第一次快,因为需要的数据都已被缓存,不需要在遍历删除表了。

下一步骤


在代码有更新的时候,你就应该运行测试用例。但你创测试用例库时,如有将它们分组。测试用例可以被分组为项目或套件。更多信息请查看:如何组织测试用例

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题,总结出来的一套通用的解决方案。
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容易使用。
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候,所有依赖者都会自动收到通知。
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
状态模式允许对象在内部状态改变时,改变它的行为,对象看起来好像改变了它的类。
命令模式将请求封装为对象,能够支持请求的排队执行、记录日志、撤销等功能。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。 基本介绍 **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为
享元模式(Flyweight Pattern)(轻量级)(共享元素)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结