单元测试包含 Environment.Exit() 调用的方法



我有一个公共方法说,

public void ErrorEncounter()
{
//Global Error Counter
gblErrorCount++;
//Process tremination
Environment.Exit();
}

此方法在调用时终止。但是,它将更新我应该测试的全局错误计数。有没有办法对这种方法执行单元测试?

我正在使用NUnit框架进行单元测试。

此方法设计为难以测试!

最明显的是,因为它在调用时终止应用程序。但也因为它改变了一个全局(我假设是静态的)变量。这两件事都会阻止编写调用该方法的良好单元测试。

解决此问题的三种方法: 1.消除方法 2. 不要测试方法 3. 修改方法

选项 1.如果此方法仅调用 exit,那么您可以简单地删除它并直接调用 Exit。但是,这将使其他一些方法难以测试,因此这不是一个好的选择。

选项 2.有时一种方法非常简单,您可以避免对其进行测试。这是否是这种方法取决于gblErrorCount在其他地方的使用方式。但是,增加计数似乎没有效果,因为该过程会立即退出。

选项 3.修改方法和调用该方法的方法。一种方法是使用事件处理机制并在事件处理程序中终止应用。通过在运行测试时注入不同的事件处理程序,可以使其更易于测试。

IOW,这基本上是一种非常无法测试的方法。希望您能够控制被测系统并可以更改它。

此问题包含显示如何测试Environment.Exit()的答案。构造函数依赖注入

一种选择是通过接口注入它来将其转换为依赖项:

interface ITerminator
{
void Exit();
}
class RealTerminator
{
void Exit()=>Environment.Exit();
}
public class MyErrorChecker
{
ITerminator _terminator;
public class MyErrorChecker(ITerminator terminator)
{
_terminator=terminator;
}
public void ErrorEncounter()
{
//Global Error Counter
gblErrorCount++;
//Process tremination
_terminator.Exit();
}
}

测试项目将实现一个假终止器类,该类在调用Exit时设置一个标志:

class FakeTerminator:ITerminator
{
public bool Called{get;private set;}
public void Exit()
{
Called=true;
}
}

嘲笑

另一种选择是通过提取对可以在模拟类中替换的虚拟方法的调用来模拟它:

public void ErrorEncounter()
{
//Global Error Counter
gblErrorCount++;
//Process tremination
ForceExit();
}
internal virtual void ForceExit()
{
Environment.Exit();
}

测试项目可以创建一个模拟错误检查器类:

class MockErrorChecker:MyErrorChecker
{
public bool Called{get;private set;}
public override void ForceExit()
{
Called=true;
}
}

函数注入

此选项不包含在链接的问题中。将exitAction作为参数传递给默认为调用Environment.Exit()ErrorEncounter

public void ErrorEncounter(Action exitFn=null)
{
var doExit=exitFn ?? (()=>Environment.Exit());
//Global Error Counter
gblErrorCount++;
//Process tremination
doExit();
}

测试可以传递自己的函数来设置标志:

[Test]
public void Test_Exit_Is_Called
{
bool called;
void fakeExit() { called=true; }
thatClass.ErrorEncounter(fakeExit);
Assert.True(called);
}

最新更新