因为工作关系,要了解Unity上的测试工具,该工具基于Nunit框架,通过查阅资料了解到在Unity5.3中做出了一些改变,自带的只剩下单元测试工具,如果想用其他的工具比如断言、集成测试,就需要前往Unity的应用商店搜索UnityTestTools进行进行下载,期待之后的版本整合更多更强大的功能。


测试工具包含

集成测试框架Integration Test Framework
集成测试允许您在一个场景自动验证过程。在现有内容里直接在编辑器中构建测试验证报告。

断言组件Assertion component
断言组件可以让你的游戏对象给予你所期望的状态。这是一个可视化工具,不需要编写任何代码。它被设计为可扩展的,适应项目的内容和您的需要。

单元测试运行器Unit Test Runner
NUnit框架的集成编辑器允许从Unity里执行单元测试。这意味着你可以实例化GameObjects和在Unity里面操作。官方提供了一个集成的测试运行器,便于查看测试和运行的报告结果。

PS:

通过文档我们了解到Unity的测试工具一定要求在Editor文件夹下才可以使用。


测试的结果有以下几种:

1.Success成功,又分为本身测试的通过,或我们在这之前就了解将会抛出的异常,也算测试通过。

2.Timeout超时,测试没有在我们要求的时间内达成。

3.Fail失败,测试的失败,作为QA测试的同学最好在检查源代码之前,再三查看是否是自己的测试代码出现问题。

4.Ignored忽略错误,运行测试时忽略一些测试


断言组件


通过文字并不是那么好了解到具体的使用方法,下面我们通过一些案例来了解如何使用Unity中的测试工具。

在Unity测试工具中有个场景叫AssertionExampleScene,描述的是一个球体自由落体掉落在平面上。

unity 应用能力认证测试试题 unitytest_Test

我们在Sphere上找到了两个断言组件,为了便于观察,我们来看第二个断言组件,看之前我们先了解一下断言组件中都有什么功能。PS:测试组件在Inspector中点击Add Component选择Scripts--Unity Test下就可以找到了。

unity 应用能力认证测试试题 unitytest_测试工具_02

1.比较方式选择器,定义应该如何比较两个值。它决定了断言的结果。

2.测试的频率,你可以明确指定断言什么时候开始,或者在什么条件下开始。

3.自定义菜单频率选项,平时是看不到的,具体要根据2的选择,才会开启这里。

3a.多少秒以后第一次触发。

3b.是否需要重复测试。

3c.多久重复测试一次。

4.一样也是自定义菜单频率选项,但是他和3并不冲突,当你同时选择了After Period Of Time与Update的时候,就会出现两个自定义频率菜单,功能相同。

4a.在多少帧以后测试应该做的。

4b.是否需要重复测试。

4c.多久重复测试一次。

第一个用于比较的GameObject,

6.自定义选择比较器,他们定义操作类型和精度。比如当比较两个浮点数时,可选操作类型有相等,不相等,大于,小于,并且可以确定他们的精度,比如在Floating Point Error中,输入0.01,则就是精确到小数点的后两位。

7.用于比较的第二个GameObject对象,可以与另外一个GameObject比较,或者是一个静态值,或者Null值。

8.根据7中你所选择的不同而改变,当7中为GameObejct选项时,这里让您拖入另外一个GameObject,如果7中为Constant Value时,这里则让您输入具体的参数,当7选择Null则消失。

相信看完以上描述以后,对于以下的这幅图大致了解是什么意思了吧,比较的是球体对象与平面对象的Y轴值,我们断言球体的Y轴一定大于平面,说人话就是球比平面高,如果球小于平面就抛异常,我们就RUN一下来测试一些断言组件吧,在这之前记得先关闭另外一个断言组件噢。


unity 应用能力认证测试试题 unitytest_Test_03


点击播放以后我们可以查看球体做自由落体并且向平面的边缘滚去,当往下滚的时候,这时候球体的Y比平面小了,所以这时候场景停住了,停住的原因是因为在Unity的Console窗口中的Error Pause选项被选中,个人觉得这样更便于观察出错的那一刻的场景表现。如果关闭Error Pause重新播放场景,如果出现抛异常后不会再暂停。

我们来查看一下都报了什么错误。

unity 应用能力认证测试试题 unitytest_unity_04

相信了解测试的同学都看出来了,Expected为我们的期望值,Actual为实际值。实际值小于期望值,所以抛异常了。


集成测试:


说完了断言组件就不得不提一下集成测试,正是因为可以抛出异常,所以断言组件和集成测试可以配合使用。

我们来看一些场景ExampleABTests

ExampleABTests这个案例我们想测试三件事:

当角色足够近(触发碰撞)的时候,蜘蛛唤醒,走向角色

当角色的距离不满足(没有触发碰撞)的时候,蜘蛛不会唤醒

触发爆炸并且伤害角色

所以场景中三个测试,所使用两个预制PlayerPrefab EnemySpider。一个是一个角色。另外一个预制是一个蜘蛛敌人。

首先我们来看Test_PlayerReceivesDamageWhenSpiderExplodes这个测试,通过在Hierarchy下查看到除了两个预制还有一个GameObject上面绑定着一个断言组件,

断言所描述的是2秒内还没有让HP低于75的话就算测试失败。PS:蜘蛛自爆需要一定的时间,通过测试发现蜘蛛爆炸大概需要4秒时间。

unity 应用能力认证测试试题 unitytest_单元测试工具_05

我们来运行一下这个测试,点击Unity菜单栏中的UnityTestTools,然后点击Integration Test Runner打开集成测试窗口,由于我们只测试这一个测试,所以我们就选中Test_PlayerReceivesDamageWhenSpiderExplodes测试,然后点击窗口中的Run Selected,可以看到测试失败了,因为玩家的HP并没有在2秒内受到伤害,从下图可以看到HP并没有改变,依旧是75,所以测试失败。

unity 应用能力认证测试试题 unitytest_Test_06

我们改变一下断言中的时间把2秒设置为5秒,这样蜘蛛就有充分的时间来引爆,修改以后保存,我们再运行一次,这次可以看到蜘蛛爆炸把人物炸飞了并且HP也扣了,所以测试自然也通过了。

unity 应用能力认证测试试题 unitytest_测试工具_07

其他两个测试:

Test_SpiderSleepsWhenPlayerNotInRange---角色在蜘蛛可触发攻击的视野范围以外,确保它不会攻击玩家

我们打开发现其中多了一个立方体上绑定着一个代码Call Testing,根据描述可以知道当碰撞盒触发的时候则算是失败,失败则为假(False)。

验证是通过如果蜘蛛触发了物体CubeCollisionFailure的碰撞器则说明测试失败,因为触发了说明它会跑向角色,这不是我们想要的,所以断言中我们采用了布尔类型,我们断言蜘蛛不会开启(不开启则为False)移动攻击控制器(跑向玩家并攻击),测试证明它确实不会,因为断言的两个对象都为False。

unity 应用能力认证测试试题 unitytest_unity 应用能力认证测试试题_08

unity 应用能力认证测试试题 unitytest_unity_09

Test_SpiderWakesWhenPlayerInRange

因为差不多所以我们就不再多说。
玩家在蜘蛛的视野范围以内。蜘蛛醒来,开始朝着这名玩家。在蜘蛛和玩家之间有一个叫Testing.Succeed()的碰撞。当蜘蛛走向这个立方体的时候成功碰撞
球员,踩上了触发器Trigger,测试通过。


单元测试

下载的插件中案例Sample.cs包含显示基本的NUnit用法示例,学习Nunit的同学可以前往http://www.36sign.com/nunit/setup.html,这个是中文的文档,相比起看英文容易的多。

由于我更新到了Unity5.3,单元测试被集成到系统中,点击菜单栏中的Windows找到Editor Test Runner就是单元测试工具了!

官方的例子Sample.cs已经有了很多的例子,因为文字太多不太好看,我们做一个简单的例子。

在Asset下创建文件夹Editor,然后右键在文件夹下创建Editor Test C#Scripts,名字我们就默认的NewEditorTest就好了。

代码如下,

using UnityEngine;
using UnityEditor;
using NUnit.Framework;


public class NewEditorTest {

    [Test]
    public void EditorTest()
    {
        int i = 2;
        int j = i + 1;
        Assert.AreEqual(3, j);
    }
}

其实就是断言J是否等于3,我们打开单元测试窗口(Editor Test Runner),可以看到里面就有我们刚刚输入的代码了我们运行一下,发现全绿了,通过。

unity 应用能力认证测试试题 unitytest_测试工具_10

那这时候我们回到代码,把3改成4,可以看到抛异常了,如下图:

unity 应用能力认证测试试题 unitytest_测试工具_11

理想的答案是4,但是J等于3呀,所以抛异常,我们接着修改代码,来测试一下已知的抛异常。

using UnityEngine;
using UnityEditor;
using NUnit.Framework;
using System;

public class NewEditorTest {

    [Test]
    [ExpectedException(typeof(ArgumentException), ExpectedMessage = "expected message")]
    public void ExpectedExceptionTest()
    {
        throw new ArgumentException("expected message");
    }
}

通过测试也通过了,更多的需要同学们去学习Nunit才知道噢。


测试输出XML

最后我们来说说怎样输出测试XML,我们打开场景ExampleABTests,

这三个测试都是通过的,为了更直观,我们把Test_SpiderSleepsWhenPlayerNotInRange下的GameObject中的断言改为True,已知蜘蛛敌人是不会触发碰撞盒的,所以测试肯定是失败咯。

我们点击菜单栏中的Unity Test Tools--Platform Runner--Run On Platform

unity 应用能力认证测试试题 unitytest_unity_12

我这里直接选择测试平台为Windows方便查看,点击build and run tests,程序会自动运行,并且执行测试。

根据提示可以了解哪个场景出现问题,并且是哪一个GameObject,期望值是什么,实际值是什么。


由于我刚才设置输出文档为项目的根目录文件夹,前往文件夹就可以看到了

unity 应用能力认证测试试题 unitytest_unity_13


打开就可以看到刚才三个测试的结果报告以及平台和版本以及时间和期望值与实际值和抛异常的位置。

unity 应用能力认证测试试题 unitytest_Test_14


最后总结一下,Unity测试工具的优点把。通过几天的琢磨,这个工具的优点在于很多地方不需要去编译任何一句代码便可以实现我们所需要的测试行为,比如这个函数所表现的是怪在不进入视野范围内是不会触发攻击的,但是却启用了攻击函数,这就证明了代码是有缺陷的,单元测试虽然小,但是把一个个模块分开来化繁为简,早一些发现问题,不至于在之后慌不择路,测试是一门很深的学问,所想的东西甚至比开发所想的要更多,加油吧。