如何使用 Moq 和 C# mock.SingleOrDefault()

how to mock.SingleOrDefault() with Moq and C#

我已经看到一些类似这样的问题,但我正在寻找一个很好的解释来解决这个问题。我知道 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
    }
}

模拟只需要 return 一个集合,该集合将允许 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));

通过让模拟 return 成为实际的 List<Thing>,当

var thing = listOfthings.MyList.SingleOrDefault(lt => lt.Name== "NameToFind");

被调用,SingleOrDefault 扩展作用于一个列表,我可以在其中按预期行事。