我个人认为有几个关键原则。
在可能的情况下,测试应该假设它们之前已经运行过并且失败了。
一些测试想要验证一个特性,而另一些则需要在测试其他东西的过程中“通过”一个特性。
我可以横向扩展并使用多台机器,这样我就可以并行运行很多测试,而且我一次运行没有时间限制。
考虑到这些,我会在可能的情况下:
- 让每个测试为自己生成不依赖于先前测试通过的唯一数据
- 将执行逻辑与验证代码分开
因此,对于您的示例,我将为您的每个操作创建并执行六个单独的“对象”:注册支持票证、添加评论、回复更多信息请求、上传附加信息和关闭票证。
然后我会在六个测试用例中将它们串在一起,如下所示:
- 注册支持票并验证
- 注册支持票,然后添加评论并验证
- 注册支持票,然后添加评论,回复请求以获取更多信息并验证
- 注册支持票,然后添加评论,回复请求以获取更多信息,上传更多信息并验证
- 注册支持票,然后添加评论,回复请求以获取更多信息,上传更多信息评论问题已修复验证
- 注册支持票,然后添加评论,回复请求以获取更多信息,上传更多信息评论,问题已修复,关闭并验证
当我测试注册 6 次时,我会构建一个测试数据对象,并且每次使用不同的测试数据,这样我每次注册时也可以测试不同的场景。
所以主要的“成本”是执行时间,因为我执行 6 个长测试而不是一个(但使用开源工具意味着我可以轻松扩展)对象的使用意味着我没有到处都有大量重复的代码。这也意味着如果应用程序的注册票部分发生更改,我只在一个地方更改一个对象,所有测试都会继续运行。
这是使用“ Parkcalc ”的单个“对象”的代码中的这种方法。
[TestMethod]
public void EconomyLessThanOneHour()
{
Parking.CalculateAndVerify(ParkingType.EconomyParking, "10:00", "AM", "today", "10:59", "AM", "today");
}
[TestMethod]
public void EconomyExactlyOneHour()
{
Parking.CalculateAndVerify(ParkingType.EconomyParking, "10:00", "AM", "today", "11:00", "AM", "today");
}
[TestMethod]
public void EconomyMoreThanOneHour()
{
Parking.CalculateAndVerify(ParkingType.EconomyParking, "10:00", "AM", "today", "11:01", "AM", "today");
}
[TestMethod]
public void EconomyJustLessThanOneDay()
{
Parking.CalculateAndVerify(ParkingType.EconomyParking, "10:00", "AM", "today", "9:59", "AM", "today+1");
}
public void EconomyExactlyOneDay()
{
Parking.CalculateAndVerify(ParkingType.EconomyParking, "10:00", "AM", "today", "10:00", "AM", "today+1");
}
[TestMethod]
public void EconomyJustMoreThanOneDay()
{
Parking.CalculateAndVerify(ParkingType.EconomyParking, "10:00", "AM", "today", "10:01", "AM", "today+1");
}
[TestMethod]
public void EconomyJustLessThanOneWeek()
{
Parking.CalculateAndVerify(ParkingType.EconomyParking, "10:00", "AM", "today", "9:59", "AM", "today+7");
}
以及CalculateAndVerify的实现......
namespace Parkcalc.Logical
{
public class Parking
{
public static void OpenHome()
{
Physical.NavigateTo.Homepage();
}
public static void Calculate(ParkingType parkingType, string inTime, string inAMPM, string inDate, string outTime, string outAMPM, string outDate)
{
inDate = Utility.CalculateDate(inDate);
outDate = Utility.CalculateDate(outDate);
Physical.Parking.Calculate(parkingType, inTime, inAMPM, inDate, outTime, outAMPM, outDate);
}
public static void CalculateAndVerify(ParkingType parkingType, string inTime, string inAMPM, string inDate, string outTime, string outAMPM, string outDate)
{
Calculate(parkingType, inTime, inAMPM, inDate, outTime, outAMPM, outDate);
Verification.Verify.VerifyResult(parkingType, inTime, inAMPM, inDate, outTime, outAMPM, outDate);
}
}
}
和下一层
namespace Parkcalc.Physical
{
public static class Parking
{
public static void Calculate(ParkingType parkingType, string inTime, string inAMPM, string inDate, string outTime, string outAMPM, string outDate)
{
NavigateTo.Homepage();
Browser.SetValue(Controls.ParkingCalculator.ddlLot,EnumValues.GetParkingType(parkingType));
if (!string.IsNullOrEmpty(inTime))
{
Browser.SetValue(Controls.ParkingCalculator.txtEntryTime, inTime);
}
if (!string.IsNullOrEmpty(inAMPM))
{
Browser.SetValue(Controls.ParkingCalculator.rdoEntryTimeAMPM, inAMPM);
}
if (!string.IsNullOrEmpty(inDate))
{
Browser.SetValue(Controls.ParkingCalculator.txtEntryDate, inDate);
}
if (!string.IsNullOrEmpty(outTime))
{
Browser.SetValue(Controls.ParkingCalculator.txtExitTime, outTime);
}
if (!string.IsNullOrEmpty(outAMPM))
{
Browser.SetValue(Controls.ParkingCalculator.rdoExitTimeAMPM, outAMPM);
}
if (!string.IsNullOrEmpty(outDate))
{
Browser.SetValue(Controls.ParkingCalculator.txtExitDate, outDate);
}
Browser.Invoke(Controls.ParkingCalculator.btnCalculate);
}
public static string GetResult()
{
return Browser.GetValue(Controls.ParkingCalculator.txtResult);
}
}
}
我在这里有一个使用 WatiN 的完整 C# 示例... http://testingstax.codeplex.com/SourceControl/changeset/view/7938#
对于测试数据,我通常会构建一个数据生成器并添加唯一的随机字符串,这样就不会发生数据冲突。