C# 使用Moq模拟Fluent接口
我已经看了很多关于这个主题的问题,但是没有一个能解决我所面临的问题 我有一些代码看起来有点像这样C# 使用Moq模拟Fluent接口,c#,unit-testing,moq,fluent,C#,Unit Testing,Moq,Fluent,我已经看了很多关于这个主题的问题,但是没有一个能解决我所面临的问题 我有一些代码看起来有点像这样 IBaseDataCollector<MyClass> myDataCollector; myDataCollector = new Mock<IBaseDataCollector<MyClass>>(); systemUnderTest = new Thing(myDataCollector.Object); 其中SomeMethod()和SomeSeco
IBaseDataCollector<MyClass> myDataCollector;
myDataCollector = new Mock<IBaseDataCollector<MyClass>>();
systemUnderTest = new Thing(myDataCollector.Object);
其中SomeMethod()
和SomeSecondMethod()
都返回this
(即myDataCollector的实例)
当我运行测试时,我在调用myDataCollector
的地方得到一个NullReferenceException
我试着在我的测试设置中添加这个
myDataCollector.Setup(_=> _.SomeMethod()),Returns(myDataCollector.Object);
但它甚至无法编译,抱怨它“无法解析方法‘Returns(acollector)’”
现在,如果我重构我的东西
类来阅读
myDataCollector.SomeMethod();
myDataCollector.SomeSecondMethod()
var collection = myDataCollector.GetData();
我的测试执行正常
如果是这样的话,我只需要重构我的代码,继续生活,但实际上,我需要在SelectMany
call中调用我的代码
var collection = list.SelectMany(_=> myDataCollector.SomeMethod()
.SomeSecondMethod(_)
.GetData());
同样,我知道我可以用ForEach
替换SelectMany
,并用调用GetData()
的每次迭代结果手动填充集合,这样我就可以去掉调用中的fluent元素,但这意味着重构代码只是为了让测试工作,这感觉不对
我应该如何在模拟对象上调用Setup()
,以使我的流畅调用正常工作?看看下面的测试代码(我发明了一些细节来填补空白)。模拟对象实例应该作为一个值从它自己的方法返回,如图所示
public class UnitTestExample
{
[Fact]
public void UnitTestExample1()
{
var myClassInterfaceMock = new Mock<IInterface<MyClass>>();
var instance = myClassInterfaceMock.Object;
var myList = new List<MyClass>()
{
new MyClass() { Attribute = 1 }
};
myClassInterfaceMock.Setup(_ => _.SomeMethod()).Returns(instance);
myClassInterfaceMock.Setup(_ => _.SomeSecondMethod()).Returns(instance);
myClassInterfaceMock.Setup(_ => _.GetData()).Returns(myList);
var myDependentClass = new MyDependentClass(instance);
var result = myDependentClass.DoTheThing();
Assert.True(result.Count.Equals(1));
}
}
public interface IInterface<T>
{
IInterface<T> SomeMethod();
IInterface<T> SomeSecondMethod();
List<T> GetData();
}
public class MyClass
{
public int Attribute { get; set; }
}
public class MyDependentClass
{
private readonly IInterface<MyClass> _test;
public MyDependentClass(IInterface<MyClass> test)
{
_test = test;
}
public List<MyClass> DoTheThing()
{
return _test.SomeMethod().SomeSecondMethod().GetData();
}
}
公共类单元测试示例
{
[事实]
public void UnitTestExample1()
{
var myClassInterfaceMock=new Mock();
var instance=myClassInterfaceMock.Object;
var myList=新列表()
{
新建MyClass(){Attribute=1}
};
myClassInterfaceMock.Setup(\u=>\ u0.SomeMethod())。返回(实例);
myClassInterfaceMock.Setup(\u=>\ u0.SomeSecondMethod())。返回(实例);
myClassInterfaceMock.Setup(\u=>\ u0.GetData()).Returns(myList);
var myDependentClass=新的myDependentClass(实例);
var result=myDependentClass.DoTheThing();
Assert.True(result.Count.Equals(1));
}
}
公共接口接口
{
i接口方法();
i接口SomeSecondMethod();
List GetData();
}
公共类MyClass
{
公共int属性{get;set;}
}
公共类MyDependentClass
{
专用只读接口测试;
公共MyDependentClass(接口测试)
{
_测试=测试;
}
公共列表DoTheThing()
{
返回_test.SomeMethod().SomeSecondMethod().GetData();
}
}
也许SetReturnsDefault
会有所帮助。看看亚当,当我试着像你一样设置它时,我仍然得到“无法解决”的错误。然后我注意到在我的界面中,我的fluent调用返回的是BaseDataCollector
,而不是ibacollector
。也就是说,如果我真的找到了解决方案,如果没有你的努力,我会花更长的时间。非常感谢。很高兴它成功了!这感觉就像是在转移视线,有时你只需要另一双眼睛。干杯
public class UnitTestExample
{
[Fact]
public void UnitTestExample1()
{
var myClassInterfaceMock = new Mock<IInterface<MyClass>>();
var instance = myClassInterfaceMock.Object;
var myList = new List<MyClass>()
{
new MyClass() { Attribute = 1 }
};
myClassInterfaceMock.Setup(_ => _.SomeMethod()).Returns(instance);
myClassInterfaceMock.Setup(_ => _.SomeSecondMethod()).Returns(instance);
myClassInterfaceMock.Setup(_ => _.GetData()).Returns(myList);
var myDependentClass = new MyDependentClass(instance);
var result = myDependentClass.DoTheThing();
Assert.True(result.Count.Equals(1));
}
}
public interface IInterface<T>
{
IInterface<T> SomeMethod();
IInterface<T> SomeSecondMethod();
List<T> GetData();
}
public class MyClass
{
public int Attribute { get; set; }
}
public class MyDependentClass
{
private readonly IInterface<MyClass> _test;
public MyDependentClass(IInterface<MyClass> test)
{
_test = test;
}
public List<MyClass> DoTheThing()
{
return _test.SomeMethod().SomeSecondMethod().GetData();
}
}