我希望测试查询第三方库的方法。该库返回一个具有IReadOnlyCollection
属性的对象。
没有构造函数来设置属性的值,并且对象没有我可以模拟的接口。
我使用Moq
来模拟我调用的服务的界面,但我无法创建模拟的返回值,因为我无法设置属性。
public interface IHitService {
public Hit GetHit();
}
public class Hit {
public Hit() {
}
public IReadOnlyCollection<string> Result { get; }
}
public class TestingClass {
public void MyTest() {
Hit hit = new Hit() {
// cannot set this property
Result = new List<string>() { "hello","goodbye" };
}
Mock<IHitService> service = new Mock<IHitService>();
service.Setup(c => c.GetHit).Returns(hit);
}
}
生成返回值以测试方法的最佳方法是什么?使用new
属性包装对象以隐藏基础不起作用。
答案 0 :(得分:2)
如果您需要测试第三方库,最好创建自己的抽象(接口)并依赖于测试和实际代码:
public interface IHitService
{
IHit GetHit();
}
public interface IHit
{
IReadOnlyCollection<string> Result { get; }
}
在您的应用程序代码中,您可以通过委派具体的第三方类来创建一个实现IHit
的简单包装类。现在,您可以根据需要通过模拟来测试界面。
答案 1 :(得分:2)
您可以使用允许您更改具体对象行为的单元测试框架,例如在这种情况下我使用Typemock Isolator尝试解决您的问题,它允许您更改结果的返回值财产所以可以&#34;设置&#34;在不更改代码或添加额外代码的情况下进行测试:
public void TestMethod1()
{
List<string> s = new List<string> { "sfas", "asfsa", "blbba" };
var hit = Isolate.Fake.NextInstance<Hit>();
Isolate.WhenCalled(() => hit.Result).WillReturnCollectionValuesOf(s);
}
在这个测试中,我模拟了Hit类,并将Result属性的返回值修改为我创建的字符串列表。
答案 2 :(得分:1)
一般情况下,如果您无法更改第三方代码,请为其构建适配器并使用您自己的抽象: -
public interface IHit
{
IReadOnlyCollection<string> Result { get; }
}
public interface IHitService
{
IHit GetHit();
}
public class HitAdapter : IHit
{
private Hit _hit;
public HitAdapter(Hit hit)
{
_hit = hit;
}
public IReadOnlyCollection<string> Result => _hit.Result;
}
public class TestingClass
{
public void MyTest()
{
var hitMock = new Mock<IHit>();
hitMock.Setup(c => c.Result).Returns<IReadOnlyCollection<string>>(x => new List<string>() {"hello", "goodbye"});
var service = new Mock<IHitService>();
service.Setup(c => c.GetHit()).Returns<IHit>(x => hitMock.Object);
}
}