C# 基于对象的模拟集返回类型';s属性而不是其引用

C# 基于对象的模拟集返回类型';s属性而不是其引用,c#,unit-testing,mocking,nsubstitute,C#,Unit Testing,Mocking,Nsubstitute,由于模拟框架(NSubstitute)的工作方式,我在单元测试中面临一个问题 我想测试一个接收参数的方法,在该方法中,我使用new操作符创建一个新对象,并将这个新对象传递给一个构建器,该构建器将构建另一个对象。我的问题是,我无法模拟构建器返回我想要的内容,因为当我配置返回对象时,它将基于引用来执行 因此,如果我新创建的对象如下所示: class MyReferenceType { public String Property1 { get; set; } public Stri

由于模拟框架(
NSubstitute
)的工作方式,我在单元测试中面临一个问题

我想测试一个接收参数的方法,在该方法中,我使用new操作符创建一个新对象,并将这个新对象传递给一个构建器,该构建器将构建另一个对象。我的问题是,我无法模拟构建器返回我想要的内容,因为当我配置返回对象时,它将基于引用来执行

因此,如果我新创建的对象如下所示:

class MyReferenceType
{
    public String Property1 { get; set; }

    public String Property2 { get; set; }

    public String Property3 { get; set; }
}
如果我的mock,我会创建一个类型为
MyReferenceType
的新对象,我会这么说

myBuilder.Build(myReferenceTypeObject).Returns(anotherObject);
在我的方法中,对象
myReferenceTypeObject
将有另一个引用,并且它不会返回我想要的对象

那么,有没有办法根据对象的属性内容而不是引用来配置模拟的返回对象呢

下面是一些代码:

class Mapper
{
    private Builder builder;
    public Mapper(Builder builder)
    {
        this.builder = builder;
    }

    public string Map(string data)
    {
        //process the string 

        MyReferenceType obj = new MyReferenceType();

        return this.builder.Build(obj);
    }
}

没有办法使引用匹配。在被测试的方法之外,您无法控制该对象,因为它正在该方法内初始化

对参数使用
Arg.Any()
,使模拟期望在执行时更灵活,因为它将忽略传递的特定参数

根据提供的代码示例,一个简单的测试如下

//Arrange
var data = "some data";
var myBuilder = Substitute.For<Builder>();
var expected = "some value";
myBuilder.Build(Arg.Any<MyReferenceType>()).Returns(expected);

var subject = new Mapper(myBuilder);

//Act
var actual = subject.Map(data);

//Assert
Assert.AreEqual(expected, actual);
//排列
var data=“一些数据”;
var myBuilder=Substitute.For();
var expected=“some value”;
myBuilder.Build(Arg.Any()).Returns(预期值);
var subject=新映射器(myBuilder);
//表演
var实际值=subject.Map(数据);
//断言
断言.AreEqual(预期、实际);
这将允许模拟在调用时按预期的方式运行

如果要有条件地匹配参数,请使用
Arg.Is(谓词条件)

myBuilder
.Build(Arg.Is(=>.Property1==“value1”&&&.Property2==“value2”))
.回报(预期);
如果传递的参数满足预期条件,则行为应与上述预期相同


参考

这不是对问题的回答,而是测试中的另一种方法,它消除了您面临的问题

不要创建模拟,而是使用
Builder
的实际实现,这样您的测试将非常简单

// Arrange
var givenData = "some data";
var expected = "transformed data";

var builder = new Builder();
var mapper = new Mapper(builder);

// Act
var actual = mapper.Map(data);

// Assert
actual.Should().Be(expected);
使用
Builder
的实际实现将使您能够在
Map
方法中进行更改,并在不更改测试的情况下更改
Builder


只模拟类/方法,这会使您的测试速度变慢。

您能提供一个我们可以测试的完整示例吗?这将使验证解决方案更加容易。@DaisyShipton这里有什么是
Builder
?尝试使用它的测试在哪里?理想情况下,我们应该能够复制、粘贴、编译和运行示例,而无需猜测任何其他内容。。。但这是一个简单的版本。。。我想没有人把所有的生产代码都放在这里。。。您可以看到builder.Build()将从MyReferenceTypeI类型返回一个字符串,我没有要求您发布整个生产代码。我要求你发布一个完整的例子。是的,我可能会花更多的时间猜测其余的代码是什么样子,但是a)我可能猜错了,浪费了每个人的时间;b) 一个人(请求帮助的人)花一点时间在问题中列出一个完整的例子要比每个试图帮助你的人都不得不这样做更合适。
// Arrange
var givenData = "some data";
var expected = "transformed data";

var builder = new Builder();
var mapper = new Mapper(builder);

// Act
var actual = mapper.Map(data);

// Assert
actual.Should().Be(expected);