有单元测试和集成测试。单元测试是测试单个组件/类/方法/函数以及它们之间的交互,但只有一个真实对象(被测系统-SUT)和测试替身。测试替身可以分为存根和模拟。存根向 SUT 提供准备好的测试数据。这样您就可以将 SUT 与环境隔离。因此,您不必访问数据库、Web 或 wcf 服务等,并且每次都有相同的输入数据。模拟用于验证 SUT 是否按预期工作。 SUT 在模拟对象上调用方法,甚至不知道它不是真实对象。然后,您通过在模拟对象上断言来验证 SUT 是否有效。您可以手动编写存根和模拟,也可以使用许多模拟框架之一。其中之一是http://code.google.com/p/moq/
如果您想测试与数据库的交互,那是集成测试,通常要困难得多。对于集成测试,您必须在众所周知的状态下设置外部资源。
让我们来看看你的图层:
您将无法对其进行单元测试。页面是紧密耦合到 ASP.NET 运行时的。您应该尝试在代码中没有太多代码。只需从您的代码中调用一些对象并测试这些对象。您可以查看 MVC 设计模式。如果您必须测试您的页面,您应该查看http://watin.org/。它自动化您的互联网浏览器,点击页面上的按钮并验证该页面显示预期结果。
这是集成测试。您将数据放入数据库中,然后将其读回并比较结果。测试之后或测试之前您必须将测试数据库置于众所周知的状态,以便测试可重复。我的建议是在测试运行之前而不是在测试运行之后设置数据库。这样您就可以在测试失败后检查数据库中的内容。
我真的不知道这与第 1 点有何不同。 2.
这是单元测试。在测试中创建对象,调用它的方法并验证结果。
第 2 点中介绍了如何测试连接到数据库的方法。
如何不浪费时间?这将伴随着经验而来。除了不要测试没有任何逻辑的属性之外,我没有一般性建议。
有关单元测试的详细信息,请看这里:
http://artofunittesting.com/
http://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/0321146530
http://www.amazon.com/Growing-Object-Oriented-Software-Guided-Tests/dp/0321503627/ref=sr_1_2?ie=UTF8&s=books&qid=1306787051&sr=1-2
http://www.amazon.com/xUnit-Test-Patterns-Refactoring-Code/dp/0131495054/ref=sr_1_1?ie=UTF8&s=books&qid=1306787051&sr=1-1
编辑:
SUT、CUT - 被测系统或类。这就是你测试的。
测试双打 - 来自特技双打。他们在电影中制作危险场景,这样真正的演员就不必这样做了。同样在这里。测试替身替换测试中的真实对象,以便您可以将测试中的 SUT/CUT 与环境隔离。
让我们看看这个类
public class NotTestableParty
{
public bool ShouldStartPreparing()
{
if (DateTime.Now.Date == new DateTime(2011, 12, 31))
{
Console.WriteLine("Prepare for party!");
return true;
}
Console.WriteLine("Party is not today");
return false;
}
}
你将如何测试这门课在新年前夜的表现是否正确?你必须在新年前夜这样做:)
现在看看修改后的 Party 类
存根示例:
public class Party
{
private IClock clock;
public Party(IClock clock)
{
this.clock = clock;
}
public bool ShouldStartPreparing()
{
if (clock.IsNewYearsEve())
{
Console.WriteLine("Prepare for party!");
return true;
}
Console.WriteLine("Party is not today");
return false;
}
}
public interface IClock
{
bool IsNewYearsEve();
}
public class AlwaysNewYearsEveClock : IClock
{
public bool IsNewYearsEve()
{
return true;
}
}
测试中你可以把假时钟传给Party课
var party = new Party(new AlwaysNewYearsEveClock());
Assert.That(party.ShouldStartPreparing(), Is.True);
现在你知道你的派对课在新年前夜是否有效。 AlwaysNewYearsEveClock 是一个存根。
现在看看这个类:
public class UntestableCalculator
{
private Logger log = new Logger();
public decimal Divide(decimal x, decimal y)
{
if (y == 0m)
{
log.Log("Don't divide by 0");
}
return x / y;
}
}
public class Logger
{
public void Log(string message)
{
// .. do some logging
}
}
您将如何测试您的班级记录消息。取决于您记录它的位置您必须检查文件或数据库或其他地方。那不是单元测试,而是集成测试。为了单元测试你这样做。
public class TestableCalculator
{
private ILogger log;
public TestableCalculator(ILogger logger)
{
log = logger;
}
public decimal Divide(decimal x, decimal y)
{
if (y == 0m)
{
log.Log("Don't divide by 0");
}
return x / y;
}
}
public interface ILogger
{
void Log(string message);
}
public class FakeLogger : ILogger
{
public string LastLoggedMessage;
public void Log(string message)
{
LastLoggedMessage = message;
}
}
在测试中你可以
var logger = new FakeLogger();
var calculator = new TestableCalculator(logger);
try
{
calculator.Divide(10, 0);
}
catch (DivideByZeroException ex)
{
Assert.That(logger.LastLoggedMessage, Is.EqualTo("Don't divide by 0"));
}
你在这里断言假记录器。假记录器是模拟对象。