模拟方法 return 只读值 属性
Mock method return value with read only property
我想测试一个查询第三方库的方法。库 return 是一个带有 IReadOnlyCollection
属性 的对象。
没有构造函数来设置 属性 的值,对象也没有可供我模拟的接口。
我已经使用 Moq
模拟我调用的服务的接口,但我无法创建模拟的 return 值,因为我无法设置 属性 .
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);
}
}
生成 return 值以测试我的方法的最佳方法是什么?用 new
属性 包裹对象以隐藏底座不起作用。
如果您需要测试第三方库,最好创建自己的抽象(接口)并在测试和实际代码中依赖它:
public interface IHitService
{
IHit GetHit();
}
public interface IHit
{
IReadOnlyCollection<string> Result { get; }
}
在您的应用程序代码中,您可以创建一个简单的包装器 class,它通过委托给具体的第三方 class 来实现 IHit
。现在您可以根据需要通过模拟来测试界面。
一般来说,如果您不能更改第 3 方代码,请为其构建一个适配器并使用您自己的抽象 :-
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);
}
}
您可以使用允许您更改具体对象行为的单元测试框架,例如在这种情况下,我使用 Typemock Isolator 来尝试解决您的问题,它允许您更改 return 结果的值 属性 因此可以 "set" 进行测试,而无需更改代码或添加额外代码:
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 class 并将结果 属性 的 return 值修改为我创建的字符串列表。
我想测试一个查询第三方库的方法。库 return 是一个带有 IReadOnlyCollection
属性 的对象。
没有构造函数来设置 属性 的值,对象也没有可供我模拟的接口。
我已经使用 Moq
模拟我调用的服务的接口,但我无法创建模拟的 return 值,因为我无法设置 属性 .
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);
}
}
生成 return 值以测试我的方法的最佳方法是什么?用 new
属性 包裹对象以隐藏底座不起作用。
如果您需要测试第三方库,最好创建自己的抽象(接口)并在测试和实际代码中依赖它:
public interface IHitService
{
IHit GetHit();
}
public interface IHit
{
IReadOnlyCollection<string> Result { get; }
}
在您的应用程序代码中,您可以创建一个简单的包装器 class,它通过委托给具体的第三方 class 来实现 IHit
。现在您可以根据需要通过模拟来测试界面。
一般来说,如果您不能更改第 3 方代码,请为其构建一个适配器并使用您自己的抽象 :-
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);
}
}
您可以使用允许您更改具体对象行为的单元测试框架,例如在这种情况下,我使用 Typemock Isolator 来尝试解决您的问题,它允许您更改 return 结果的值 属性 因此可以 "set" 进行测试,而无需更改代码或添加额外代码:
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 class 并将结果 属性 的 return 值修改为我创建的字符串列表。