简体   繁体   English

对其中包含Environment.Exit()调用的方法进行单元测试

[英]Unit Testing a method containing Environment.Exit() call within it

I have a public method say, 我有一个公开的方法说,

public void ErrorEncounter()
{
//Global Error Counter
gblErrorCount++;

//Process tremination
Environment.Exit();
}

This method terminates whenever it is called. 每当调用此方法时,该方法就会终止。 However, it will update the Global Error Count which i'm suppose to test. 但是,它将更新我应该测试的全局错误计数 Is there any way to perform Unit Testing on this method? 有什么方法可以对此方法执行单元测试吗?

I'm Using NUnit Framework for Unit Testing. 我正在使用NUnit Framework进行单元测试。

This method is designed to be difficult to test! 设计这种方法很难测试!

Most obviously, because it terminates the application when called. 最明显的是,因为它在被调用时会终止应用程序。 But also because it changes a global (I assume static) variable. 也是因为它更改了全局变量(我假设是静态的)。 Both of these things prevent writing a good unit test that calls the method. 这两件事都会阻止编写好的方法调用单元测试。

Three ways around this: 1. Eliminate the method 2. Don't test the method 3. Modify the method 三种解决方法:1.消除方法2.不测试方法3.修改方法

Option 1. If this method only called exit, then you could simply drop it and call Exit directly. 选项1.如果此方法仅调用了exit,则可以直接将其删除并直接调用Exit。 However, that would make some other method difficult to test, so this isn't really a great option. 但是,这会使其他方法难以测试,因此这并不是一个很好的选择。

Option 2. Sometimes a method is so simple that you can avoid testing it. 选项2。有时候一种方法是如此简单,以至于您可以避免对其进行测试。 Whether this is such a method depends on how gblErrorCount is used elsewhere. 这是否是这种方法取决于在其他地方如何使用gblErrorCount It would appear, however, that incrementing the count has no effect, since the process immediately exits. 但是,由于该过程立即退出,因此增加计数似乎没有效果。

Option 3. Modify the method and those methods that call it. 选项3.修改方法和调用该方法的那些方法。 One approach would be to use an event handling mechanism and terminate the app in the event handler. 一种方法是使用事件处理机制,并在事件处理程序中终止应用程序。 You could make this easier to test by injecting a different event handler when running tests. 您可以通过在运行测试时注入不同的事件处理程序来使其更易于测试。

IOW, this is basically a pretty untestable method. IOW,这基本上是一种不可测试的方法。 Hopefully, you are in control of the system under test and can change it. 希望您可以控制被测系统并可以对其进行更改。

This question contains answers that show how Environment.Exit() can be tested. 这个问题包含的答案显示了如何测试Environment.Exit() Constructor Dependency Injection 构造函数依赖注入

One option is to convert it into a dependency by injecting it through an interface : 一种选择是通过接口将其转换为依赖项:

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();
    }
}

The test project will implement a fake terminator class that sets a flag if Exit is called: 如果调用Exit ,测试项目将实现一个伪造的终结器类,该类将设置一个标志:

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

Mocking 惩戒

Another option is to mock it by extracting the call to a virtual method that can be replaced in a mock class : 另一个选择是通过提取对虚拟方法的调用来模拟它,该方法可以在模拟类中替换:

public void ErrorEncounter()
{
    //Global Error Counter
    gblErrorCount++;

    //Process tremination
    ForceExit();
}

internal virtual void ForceExit()
{
    Environment.Exit();
}

The test project could create a mock error checker class: 测试项目可以创建一个模拟错误检查器类:

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

Function injection 功能注入

This option isn't included in the linked question. 此选项不包含在链接的问题中。 Pass an exit Action as a parameter to ErrorEncounter whose default will be to call Environment.Exit() : exit Action作为参数传递给ErrorEncounter其默认设置为调用Environment.Exit()

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

        //Process tremination
        doExit();
    }

The test could pass its own function that sets a flag: 该测试可以通过自己的设置标志的函数:

[Test]
public void Test_Exit_Is_Called
{
    bool called;
    void fakeExit() { called=true; }

    thatClass.ErrorEncounter(fakeExit);

    Assert.True(called);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM