Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/320.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.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# 我如何才能假调用当前类';用NSU替代的方法?_C#_Unit Testing_Nunit_Nsubstitute - Fatal编程技术网

C# 我如何才能假调用当前类';用NSU替代的方法?

C# 我如何才能假调用当前类';用NSU替代的方法?,c#,unit-testing,nunit,nsubstitute,C#,Unit Testing,Nunit,Nsubstitute,我不熟悉NSubstitue(对.NET中的单元测试也很陌生)。我想测试我的类是否将每个条目的所有数据保存在不同的文件中,例如StringDictionary 假设我有我的类DataManipulation.cs: using System; using System.Collections; using System.Collections.Specialized; namespace ApplicationName { // interface for NSubstitute

我不熟悉NSubstitue(对.NET中的单元测试也很陌生)。我想测试我的类是否将每个条目的所有数据保存在不同的文件中,例如StringDictionary

假设我有我的类
DataManipulation.cs

using System;
using System.Collections;
using System.Collections.Specialized;

namespace ApplicationName
{
    // interface for NSubstitute
    public interface IManipulator
    {
        void saveAllData();
        void saveEntry(string entryKey, string entryValue);
    }

    public class DataManipulator : IManipulator
    {
        protected StringDictionary _data {get; private set;}

        public DataManipulator()
        {
            _data = new StringDictionary();
        }

        public void addData(string name, string data)
        {
            this._data.Add(name, data);
        }

        public void saveAllData()
        {
            // potential implementation - I want to test this
            foreach (DictionaryEntry entry in this._data)
            {
                this.saveEntry(entry.Key.ToString(), entry.Value.ToString());
            }
        }

        public void saveEntry(string entryKey, string entryValue)
        {
            // interact with filesystem, save each entry in its own file
        }
    }
}
我想测试的是:当我调用
数据操纵器.saveAllData()
时,它将每个
\u数据
条目保存在一个单独的文件中,这意味着它运行
saveEntry
的次数等于
\u数据.Count
。是否可以使用NSubstitute

每次我尝试将DataManipulation用作测试对象并单独用作模拟对象时,当我运行
Received()
时,我都会得到没有调用的信息

我要使用的NUnit测试模板:

using System;
using System.Collections.Generic;

using NUnit.Framework;
using NSubstitute;

namespace ApplicationName.UnitTests
{
    [TestFixture]
    class DataManipulatorTests
    {
        [Test]
        public void saveAllData_CallsSaveEntry_ForEachData()
        {

            DataManipulator dm = new DataManipulator();
            dm.addData("abc", "abc");
            dm.addData("def", "def");
            dm.addData("ghi", "ghi");

            dm.saveAllData();

            // how to assert if it called DataManipulator.saveEntry() three times?
        }

    }
}

或者我应该用不同的方式来做吗?

根据一些OOP原则和测试需求,您必须引入依赖项或某种构造来创建适合测试的“seam”

使用另一个依赖项作为模拟

它将封装数据存储,您将对照它检查您的断言。我建议你阅读一下假冒、存根和冒牌之间的区别

  • 添加新的存储接口和实现

    public interface IDataStorage
    {
        void Store(string key, string value);
    }
    
    public class DataStorage : IDataStorage
    {
        public void Store(string key, string value)
        {
            //some usefull logic
        }
    }
    
  • 将其用作操纵器实现中的依赖项(并通过构造函数注入)

    public class DataManipulator : IManipulator
    {
        protected IDataStorage _storage { get; private set; }
        protected StringDictionary _data { get; private set; }
    
        public DataManipulator(IDataStorage storage)
        {
            _storage = storage;
            _data = new StringDictionary();
        }
    
        public void addData(string name, string data)
        {
            this._data.Add(name, data);
        }
    
        public void saveAllData()
        {                
            // potential implementation - I want to test this
            foreach (DictionaryEntry entry in this._data)
            {
                this.saveEntry(entry.Key.ToString(), entry.Value.ToString());
            }
        }
    
        public void saveEntry(string entryKey, string entryValue)
        {
            _storage.Store(entryKey, entryValue);
        }
    }
    
  • 测试一下

    [Test]
    public void saveAllData_CallsSaveEntry_ForEachData()
    {
    
        var dataStorageMock = Substitute.For<IDataStorage>();
        DataManipulator dm = new DataManipulator(dataStorageMock);
        dm.addData("abc", "abc");
        dm.addData("def", "def");
        dm.addData("ghi", "ghi");
    
        dm.saveAllData();
    
        dataStorageMock.Received().Store("abc", "abc");
        dataStorageMock.Received().Store("def", "def");
        dataStorageMock.Received().Store("ghi", "ghi");
        //or 
        dataStorageMock.Received(3).Store(Arg.Any<string>(), Arg.Any<string>());
    }
    
    并测试它:

    [Test]
    public void saveAllData_CallsSaveEntry_ForEachData()
    {
    
        var dm = Substitute.For<DataManipulator>();
        dm.addData("abc", "abc");
        dm.addData("def", "def");
        dm.addData("ghi", "ghi");
    
        dm.saveAllData();
    
        dm.Received(3).saveEntry(Arg.Any<string>(), Arg.Any<string>());
    }
    
    [测试]
    public void saveAllData_CallsSaveEntry_ForEachData()
    {
    var dm=替换为();
    dm.addData(“abc”、“abc”);
    dm.addData(“def”、“def”);
    dm.addData(“ghi”、“ghi”);
    dm.saveAllData();
    dm.Received(3).saveEntry(Arg.Any(),Arg.Any());
    }
    
    仅仅为了测试需要而采用某种虚拟方法的需求可能不是很吸引人,但是

  • 一旦您的测试也是业务逻辑的客户机,您就可以接受它
  • 在这种情况下,可以使用一些“繁重”的测试框架,比如MS Fakes,但这似乎有些过分
  • 另一个解决方案是测试另一个工作单元,它涵盖了所描述的工作单元(可能看起来像我的第一个解决方案)
  • UPD:阅读它以更好地理解NSubstitute

    [Test]
    public void saveAllData_CallsSaveEntry_ForEachData()
    {
    
        var dm = Substitute.For<DataManipulator>();
        dm.addData("abc", "abc");
        dm.addData("def", "def");
        dm.addData("ghi", "ghi");
    
        dm.saveAllData();
    
        dm.Received(3).saveEntry(Arg.Any<string>(), Arg.Any<string>());
    }