原文: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方法。
{
;
// Create an employee instance to use in test cases.
employee = new Employee("your name");
super();
}
为Name方法这一要求添加测试用例
在这一步骤中,你将添加一个测试用例。你将为类EmployeeTest添加一个新的方法,严重epmployee的name被正确设置。
为name要求添加测试用例
1. 在AOT上,右键单击EmployeeTest类,选择New method。
2. 在代码编辑器中,按如下代码修改该方法。
{
// Verify that the employee name is set correctly.
this.assertEquals("your name", employee.name());
}
现在如果运行这个测试用例会是失败的,你可以为这一测试用例书写特征代码以完成编译并可以使测试用例运行成功。并重写Employee类的new方法以接受一个字符串作为参数。
添加特征代码
1. 在AOT上,在Employee类的classDeclaration方法节点上右键双击。
2. 在代码编辑器中,按如下代码修改声明。
{
// Create member variables.
str name;
}
3. 在AOT上,右键单击Employee 类节点,选择Override method,然后点击new。
4. 在代码编辑器中,按如下代码修改new方法。
{
;
name = _name;
}
5. 在AOT上,右键单击Employee类,点击New method。
6. 在代码编辑器中,按如下代码修改该方法。
{
;
// Return the expected string.
return name;
}
7. 在AOT上,右键单击Employee类并点击Compile。
8. 右键单击Employee类并点击Compile。
运行测试用例
在这一步骤中,你将通过单元测试工具栏来运行测试用例。运行测试用例的更多信息请查看:如何运行测试用例。
运行测试用例
- 在AOT上,右键单击EmployeeTest类,选择Add-Ins,然后点击Run tests。
注释 |
将会打开单元测试工具栏并且运行测试。由于只添加了一个测试用例,所以运行结果是‘1 run, 0 failed’。 |
在这一步骤中,你将修改测试用例以使测试失败。在TDD中,首先都是创建一个运行失败的测试用例。由于编译的原因,在这个例子中,首先便创建了运行会成功的测试用例。
使测试用例失败
1. 在AOT上,双击Employee 类的name方法节点。In the AOT, in the Employee class node, double-click the name method.
2. 在代码编辑器中,按如下代码修改该方法。
{
;
// Return the expected string.
// return name;
// Return an empty string to make the test case fail.
return "";
}
3. 在AOT中,右键单击Employee类并点击Compile。
4. 在单元测试工具栏上,点击Run按钮。
注释 |
运行结果显示‘1 run, 1 failed’。Infolog显示预期的结果和实际的结果。 Error: [EmployeeTest.testName]Failure: Assertion failed! (Expected: your name; Actual: ) |
5. 在Infolog中,可以点击Edit按钮打开代码编辑器并定位到断言失败的地方。
6. 在AOT上,双击Employee类的name方法。
7. 在代码编辑器中,按如下代码修改该方法。
{
// Return the expected string.
return name;
// Return an empty string to make the test case fail.
// return "";
}
8. 在AOT中,右键单击Employee类,并点击Compile。
为Retire需求添加测试用例
在这一步骤中,你将为退休这一需求创建测试用例。你将给EmployeeTest添加一个新的方法来完成这一测试用例。这样测试用例用于验证对应同一职员,如果retire方法被调用超过一次,将会抛出异常。同样,遵循TDD的原则,你将在写任何被测试类的实现前首先创建测试用例,所以不要编译。
为退休这一需求添加测试用例
1. 在AOT上,右键单击EmployeeTest然后点击New method。
2. 在代码编辑器中,按如下代码修改该方法。
{
;
// 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方法
1. 在AOT上,在Employee类的classDeclaration方法上双击。
2. 在代码编辑器中,为ClassDeclaration方法添加如下成员变量。
3. 在AOT上,右键单击Employee类,点击New method。
4. 在代码编辑器中,按如下代码修改该方法。
{
// If retired, throw an exception, otherwise set the retired value to true.
if (retired)
throw error("Already retired");
retired = true;
}
5. 在AOT中,右键单击Employee类点击Compile。
6. 右键单击EmployeeTest类,点击Compile。
7. 在单元测试工具栏上,点击Run按钮。
注释 |
由于添加了两个测试用例,所以运行结果显示‘2 run, 0 failed’。你可以通过不第二次调用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标签页。
3. 在Development标签页中,选择Debug组,点击Debug mode字段的下拉按钮,选择When breakpoint。
4. 在AX的系统按钮中,点击Tools/Development tools/Unit test/Parameters。
5. 在单元测试属性表中,在General标签页,勾选Record code coverage选项框。默认情况下,Database被作为记录代码覆盖率的监听器。
6. 关闭所有Form和报表。
7. 在单元测试工具栏上点击Run按钮。
8. 点击单元测试工具栏的Details按钮。
注释 |
你可以看到EmployeeTest测试用例被运行。详细信息显示测试用例运行的时间、日期、被谁运行、代码覆盖率及运行结果。 |
9. 点击General标签页。
注释 |
你将看到以毫秒为单位的EmployeeTest测试用例运行所耗时间。 |
10. 点击Environment标签页。
注释 |
你将看到EmployeeTest测试用例运行的系统环境。 |
11. 点击Tests按钮。
注释 |
在Test form的下边的窗格,可以看到方法级别的统计信息。你可以看到每一个方法的代码覆盖率。 |
设置隔离级别
根据测试用例对数据操作的不同需要设置不同的隔离级别。单元测试框架提供了4种测试套件分别提供不同的隔离级别。更多的信息,请查看单元测试框架。在这一步骤中,你将重写createSuite方法以使用SysTestSuiteCompanyIsolateClass测试套件。这一测试套件为每一个测试类创建新的空的公司账号名,每一个测试方法都在该公司下运行。
设置测试用例的隔离级别
1. 在AOT上,右键单击EmployeeTest类,点击Override method,然后点击createSuite。
2. 在代码编辑器中,在代码行 ret = super();中选择super,右键单击点击Lookup definition。
注释Note |
默认情况下,基类的createSuite方法返回SysTestSuite测试套件,它不提供任何隔离级别。 |
3. 关闭基类createSuite方法所在代码编辑器。
4. 在代码编辑器中,按如下代码修改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);
}
5. 在AOT上,右键单击EmployeeTest然后点击Compile。
6. 点击单元测试工具栏的Run按钮。
注释 |
在第一次运行测试后,所有表会被循环遍历并删除。但第二次运行测试用例时,测试用例的运行速度会比第一次快,因为需要的数据都已被缓存,不需要在遍历删除表了。 |
下一步骤
在代码有更新的时候,你就应该运行测试用例。但你创测试用例库时,如有将它们分组。测试用例可以被分组为项目或套件。更多信息请查看:如何组织测试用例。