C# 我如何才能假调用当前类';用NSU替代的方法?
我不熟悉NSubstitue(对.NET中的单元测试也很陌生)。我想测试我的类是否将每个条目的所有数据保存在不同的文件中,例如StringDictionary 假设我有我的类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
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());
}
仅仅为了测试需要而采用某种虚拟方法的需求可能不是很吸引人,但是
[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>());
}