c# - 如何使用 Moq 和 C# 模拟.SingleOrDefault()
问题描述
我已经看到了一些像这样的问题,但我正在寻找如何解决这个问题的一个很好的解释。我知道 Moq 不能模拟扩展调用,但我只是在寻找一个非常好的例子。在当前代码中,我有一个类似的调用
var thing = listOfthings.myList.SingleOrDefault(lt => lt.Name== "NameToFind");
我试过了
MockedlistOfThings.Setup(x => x.myList.SingleOrDefault(o => o.Name == "NameToFind")).Returns(fakeObject);
只是在寻找一个好的工作。谢谢。
为了进一步详细说明这种情况是如何出现的,我们目前正在针对大量数据运行一个翻译引擎,该引擎必须逐行运行。此翻译引擎传入一个名为 IListOfthings 的接口。listOfthings 实际上将参考数据保存在字典中,该字典在程序中更高的另一个调用中预加载。我创建了一个“fakeObject”<- 字典,其中包含该方法可以使用的假数据。我嘲笑了传递给调用方法的 IlistOfthings 。但我看不到如何伪造 SingleOrDefault 调用。下面的简化方法。
Public class ClassIMTesting
{
public void Translate(myObject obj, IlistOfThings listOfthings){
var thing = listOfthings.MyList.SingleOrDefault(lt => lt.Name== "NameToFind");
//Other logic here .....
}
}
public class Thing()
{
public string Name { get; set; }
public Dictionary MyDict { get; set; }
}
[TestFixture()]
public class MyCodeTest
{
MyObject myObj;
Mock<IListOfthings> listOfThings;
Thing thing;
[SetUp]
public void Setup()
{
myObj = new MyObject();
_thing = new thing();
_thing.Name = "MyName";
var myDict = new Dictionary<string, string>();
myDict.Add("70,~", "");
myDict.Add("70,145", "expectedResult");
myDict.Add("911,", "expectedResult");
thing.MyDict = myDict;
listOfThings = new Mock<IListOfthings>();
listOfThings.Setup(x => x.MyList.SingleOrDefault(o => o.Name == "MyName")).Returns(thing);
}
[TestCase("70", "~", "70070")]
[TestCase("70", "145", "expectedResult")]
[TestCase("911", "", "expectedResult")]
public void TranslateTest(string iTC, string ITCode, string expectedResult)
{
myObject.ITC = iTC;
myObject.ITCode = iTCode;
ClassIMTesting p = new ClassIMTesting();
p.Translate(myObject, listofThings.Object);
Assert.That(myObject.ITC3Code, Is.EqualTo(expectedResult));
}
}
public interface IListOfThings
{
List<Thing> MyList{ get; set; }
}
解决方案
给定
public interface IListOfThings {
List<Thing> MyList { get; set; }
}
public class Thing() {
public string Name { get; set; }
public Dictionary MyDict { get; set; }
}
为了提供一个mock来满足下面的例子
public class ClassImTesting {
public Thing Translate(IlistOfThings listOfthings){
var thing = listOfthings.MyList.SingleOrDefault(lt => lt.Name== "NameToFind");
return thing
}
}
模拟只需要返回一个集合,该集合将允许SingleOrDefault
扩展在调用时按预期运行。
例如
//Arrrange
Mock<IListOfthings> listOfThings = new Mock<IListOfthings>();
var thing = new Thing {
Name = "NameToFind",
//...
};
List<Thing> list = new List<Thing>() { thing };
listOfThings.Setup(_ => _.MyList).Returns(list);
var subject = new ClassImTesting();
//Act
var actual = subject.Translate(listOfThings.Object);
//Assert
Assert.That(actual, Is.EqualTo(thing));
通过让模拟返回一个实际的List<Thing>
,当
var thing = listOfthings.MyList.SingleOrDefault(lt => lt.Name== "NameToFind");
被调用时,SingleOrDefault
扩展作用于我可以按预期运行的列表。