Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/298.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 包装静态类/方法以便对其进行单元测试?_C#_.net_Unit Testing_Nunit_Moq - Fatal编程技术网

C# 包装静态类/方法以便对其进行单元测试?

C# 包装静态类/方法以便对其进行单元测试?,c#,.net,unit-testing,nunit,moq,C#,.net,Unit Testing,Nunit,Moq,我有一个用于日志记录的静态类: public static class myLogger { public static ErrorLogging(string input) { //dostuff } } 我使用它的方式是: public class myClassthatDoesStuff { ... myLogger.ErrorLogging("some error ocurred"); ... } 我怎样才能禁用myLo

我有一个用于日志记录的静态类:

public static class myLogger
{
    public static ErrorLogging(string input)
    {
        //dostuff
    }
}
我使用它的方式是:

public class myClassthatDoesStuff
{
    ...
    myLogger.ErrorLogging("some error ocurred");
    ...
}

我怎样才能禁用myLogger类,以便能够对其进行单元测试并确保执行了ErrorLogging方法是否可以在不设置构造函数中任何参数的情况下执行此操作(构造函数注入)?myClassthatDoesStuff要求构造函数中没有参数。

如果无法将其从静态类更改为非静态类,请使用非静态类包装它

void Test()
{
    string testString = "Added log";
    var logStore = new List<string>();
    ILogger logger = new MyTestableLogger(logStore);

    logger.ErrorLogging(testString);

    Assert.That(logStore.Any(log => log==testString));
}

public interface ILogger
{
    void ErrorLogging(string input);
}

public class MyTestableLogger : ILogger
{
    public MyTestableLogger(ICollection<string> logStore)
    {
        this.logStore = logStore;
    }

    private ICollection<string> logStore;

    public void ErrorLogging(string input)
    {
        logStore.Add(input);
        MyLogger.ErrorLogging(input);
    }
}

public static class MyLogger
{
    public static void ErrorLogging(string input)
    {
        // Persist input string somewhere
    }
}
void测试()
{
string testString=“添加日志”;
var logStore=新列表();
ILogger logger=新的MyTestableLogger(logStore);
logger.ErrorLogging(testString);
Assert.That(logStore.Any(log=>log==testString));
}
公共接口ILogger
{
无效错误记录(字符串输入);
}
公共类MyTestableLogger:ILogger
{
公共MyTestableLogger(ICollection logStore)
{
this.logStore=logStore;
}
私人ICollection logStore;
公共无效错误记录(字符串输入)
{
添加(输入);
MyLogger.ErrorLogging(输入);
}
}
公共静态类MyLogger
{
公共静态无效错误记录(字符串输入)
{
//将输入字符串保存到某个位置
}
}

您可以使用Microsoft的

假设您的项目名为
ConsoleApplication1

首先,转到单元测试项目引用,右键单击包含
MyClassThatDoesTuff
class的程序集,并选择“添加伪程序集”

使用垫片进行的单元测试如下所示:

[TestClass()]
public class MyClassthatDoesStuffTests
{
    [TestMethod()]
    public void ImportansStuffTest()
    {
        using (ShimsContext.Create())
        {
            bool logCalled = false;
            ConsoleApplication1.Fakes.ShimmyLogger.ErrorLoggingString = 
                (message) => logCalled = true;
            new myClassthatDoesStuff().ImportansStuff();
            Assert.IsTrue(logCalled);
        }
    }
}
描述了完全相同的场景-您有一个旧的静态日志记录方法,并且希望在可测试代码中使用它

  • 将静态类包装在非静态类中-不仅用于测试,还用于一般用途
  • 将新的非静态类的方法提取到接口中
  • 无论您在哪里依赖静态类,都应该依赖接口。例如,如果class
    DoesMething
    需要静态类中的函数,请执行以下操作:

    public interface ILogger
    {
        void ErrorLogging(string input);
    }
    
    public class MyClassthatDoesStuff
    {
        private readonly ILogger _logger;
    
        public MyClassthatDoesStuff(ILogger logger)
        {
            _logger = logger;
        }
    }
    
这给了您两个好处:

  • 您可以对旧的静态类进行单元测试(假设它没有状态,也不依赖于任何具有任何状态的对象)(尽管如果是这种情况,我想您还是可以对它进行单元测试)
  • 您可以单元测试将使用该静态类的代码(通过删除对该静态类的直接依赖关系)。您可以使用模拟类替换
    ILogger
    ,就像将错误消息添加到列表中的类一样

    class StringLogger : List<string>, ILogger
    {
        public void ErrorLogging(string input)
        {
           Add(input);
        }
    }
    
    var testSubject = new MyClassthatDoesStuff(new StringLogger());
    
    class StringLogger:列表,ILogger
    {
    公共无效错误记录(字符串输入)
    {
    添加(输入);
    }
    }
    var testSubject=new myclassthattowestuff(new StringLogger());
    
  • 你可以用它来做

    它允许您避免使用这么多的包装器和接口,并做到这么简单:

    [TestMethod]
    public void TestLogging()
    {
        //Arrange
        Isolate.WhenCalled(() => myLogger.ErrorLogging("")).CallOriginal();
    
        //Act
        var foo = new myClassthatDoesStuff();
        foo.DoStuff();
    
        //Assert
        Isolate.Verify.WasCalledWithAnyArguments(() => myLogger.ErrorLogging(""));
    }
    

    查看Microsoft的填隙片要求Visual Studio Ultimate,它可能是Moles的复制品,它仍然适用于VS2010-是否可以不在构造函数中设置任何参数就执行此操作(构造函数注入)?myClassthatDoesStuff要求构造函数中没有参数。如果你不能在构造函数中放入任何东西,那肯定会使它更难。如果您可以从头开始使用依赖项注入,从而可以控制类的实例化方式。例如,如果没有依赖项注入,WCF服务类的构造函数中通常不会有任何内容。scott非常感谢您对这一切的解释。有意义无需在构造函数中设置任何参数(构造函数注入)就可以做到这一点吗?myClassthatDoesStuff要求构造函数中没有参数。@l--“l”--“l”--“l”(不知道
    @
    提到的内容可能会变成这样的折磨…)您可以删除参数确定。。。但是,如何测试您添加的日志条目是否存在于数据存储中呢?:)