我们正在编写测试框架(用于集成测试),我对断言有疑问。测试代码如下:
public class MyTestClass
{
[Fact]
public void MyTest()
{
CreateEntity();
DeleteEntity();
}
}
框架代码如下:
public class CRUD
{
public bool CreateEntity()
{
FuncA();
FuncB();
FuncC();
FuncD();
}
}
如果FuncA()
失败,我不想运行FuncB()
,FuncC()
或FuncD()
。
我通常会做的是检查FuncA()
是否使用if-else语句成功执行,如果没有 - 我会返回false。
我的问题是编写测试代码的人必须手动检查CreateEntity()
是否返回true或false。因为它是测试代码,如果CreateEntity()
失败,继续测试运行没有任何实际意义。我不希望用户if-else在他的Test-Case上使用每个方法并在失败时断言。我可以在Framework方法中自己断言吗?例如 -
public class CRUD
{
public bool CreateEntity()
{
if (FuncA() == false)
{
Assert.True(false, "FuncA() has failed");
}
FuncB();
FuncC();
FuncD();
}
}
这被认为是个好主意吗?或者用户应该自己查询?我希望尽可能简化用户创建测试用例。
谢谢!
修改 需要记住的重要一点是这是一个集成测试框架。与单元测试不同,我们正在执行各种操作,并尝试了解它们如何协同工作。 FuncA()转到服务器并尝试执行操作。此操作通常不应失败。如果它有一些主要的基本功能错误,它将在我们的单元测试运行中被捕获。当它在我们的集成运行中不起作用时 - 它可能指向在特定的一组先前执行的操作之后发生的错误。所以我们想了解它,并停止测试,因为下一个动作可能无法正常工作,因为它们被集成到另一个中。所以我不确定我们是否想要模拟“CreateEntity”,因为它为我们提供了有关系统疾病的信息。我同意你的观点,Assert不是处理它的正确方法,我只是不完全确定异常是正确的方法,因为我不想处理问题,我想报告并停止测试。我不太喜欢需要用户if / else每个框架调用并检查结果的其他选项(这会在我看来会产生一个混乱的代码)。
答案 0 :(得分:0)
围绕try catch中的函数。然后抛出异常或在catch中有一些逻辑来更新对象,并提供有关失败的一些信息。我建议投掷并使对象不知情。它不应该负责处理它自己的问题
答案 1 :(得分:0)
这实际上取决于您对CRUD
课程的要求。作为一般规则,我会回应rhughes在评论中提出的建议 - 你应该明确抛出异常。在这种情况下,CreateEntity()
方法最简单的合理重写如下:
public class CRUD
{
public bool CreateEntity()
{
if (FuncA() == false)
{
throw new Exception("FuncA() has failed");
}
FuncB();
FuncC();
FuncD();
}
}
或者,FuncA()
本身可以在异常失败时抛出异常,并且您认为它不能在正常执行下失败。在任何一种情况下,这些都会导致您的测试用例失败,并且CreateEntity()
中的代码会在抛出它时停止执行。
我反对在应用程序代码中使用测试框架断言 - 如果你只是将它们添加到测试中,那么你的应用程序本身就不应该知道它们。像MSTest这样的框架无论如何都会在Assert.IsTrue
这样的方法中使用异常,所以你最终会遇到与在应用程序代码中手动抛出异常相同的行为,但最终会降低对下一个人的可读性和不太容易理解正在努力。
编辑:您是否考虑过以下方式抽象方法背后的丑陋:
private void WithEntity(Action action)
{
if (!CreateEntity())
{
throw new Exception("Failed to create entity");
}
action();
DeleteEntity();
}
然后你可以写下你的测试:
[Fact]
public void TestMethod1()
{
WithEntity(() =>
{
// test code goes here
});
}
它会掩盖一些尴尬。这样,您的应用程序代码仍然可以return false;
FuncA();
失败,并且每次要编写新测试时都不必编写大量样板文件。您甚至可以在集成测试框架中添加[Setup]
属性,以便在每个测试/套件之前运行,如下所示:
[Setup]
public void Setup()
{
if (!CreateEntity())
{
throw new Exception("Failed to create entity");
}
}
...和一个类似的[Cleanup]
属性来处理每个测试/套件后的运行代码(取决于您需要的)。这些建议中的任何一个都有帮助吗?
编辑2:另一件可以帮助的事情是装饰模式。如果您的CRUD
类实现了一个接口,那么您可以执行某种操作......
public class Crud : ICrud
{
public bool CreateEntity()
{
// exciting business logic
}
// etc.
}
public class CrudTestDecorator : ICrud
{
private readonly ICrud m_Crud;
public CrudTestDecorator(ICrud crud)
{
m_Crud = crud;
}
public bool CreateEntity()
{
if (!m_Crud.CreateEntity())
{
throw new Exception("Could not create entity");
}
}
// etc.
}
这满足了您的更多要求:
bool
s