【问题标题】:Moq an object with a nested property that doesn't have interfaceMoq 具有嵌套属性但没有接口的对象
【发布时间】:2020-08-05 00:37:29
【问题描述】:

我们有以下代码来测试它是否有效:

Car car = await someService.CreateAsync(wheels);
List<string> urls = car.Input.Endpoints.Select(x => x.Url);

现在我试图在第一行模拟 someService 返回的汽车来测试第二行。我试过这个:

var car = new Mock<Car>();
var carEndpoint = new CarEndpoint(url: "http://google.com");
car.Object.Input.Endpoints.Add(carEndpoint);

var someService = new Mock<ISomeService>();
someService.Setup(o => o.CreateAsync(It.IsAny<Wheels>())).ReturnsAsync(car.Object);

var myClass = new ClassToTest(someService.Object);
...

但是会报错

System.NotSupportedException: '不支持的表达式: ....端点 不可覆盖的成员(这里:Input.get_Endpoints)不能用于 设置/验证表达式。'

问题是 Car 是由我无法修改的 someService 创建的,而且 Car 和 Input 都没有实现任何接口。我如何模拟它以测试从顶部开始的第二行?

List<string> urls = car.Input.Endpoints.Select(x => x.Url);

根据要求,我将离开 Car 课程(简化版):

namespace X
{
    [JsonTransformation]
    public class Car : AnotherClass
    {
        public Car();
    
        public Car(CarInput input, string description, ...);

        [JsonProperty(PropertyName = "properties.description")]
        public string Description { get; set; }

        [JsonProperty(PropertyName = "properties.input")]
        public CarInput Input { get; set; }
        
        ...
    }
}

建议在没有起订量的情况下手动创建对象,这样做我们必须写很多行,首先因为第二行不是我们要测试的唯一属性(记住这是一个简化的场景),其次我们必须在任何地方放置 new 来创建嵌套属性所需的结构。既然我们不能修改 Car 类,它也没有接口,如何避免这种情况。

【问题讨论】:

  • 请发Car
  • 99% 你真的不需要模拟一辆车,简单地创造一辆就可以了……但事实上,正如@zaitsman 所说,没有实际例子,我们无能为力。
  • Car 是一个外部类,有很多属性本身就是外部对象,Input 就是其中之一,没有一个实现接口。尽管如此,我还是会添加课程。
  • @zaitsman Alexei 完成

标签: c# mocking moq


【解决方案1】:

所以考虑到 Car 或多或少是 POCO,为什么不只是

var car = new Car();
var carEndpoint = new CarEndpoint(url: "http://google.com");
car.Input = new CarInput { Endpoints = new [] { carEndpoint } }; 
// or convert the above to list or whatever you have

var someService = new Mock<ISomeService>();
someService.Setup(o => o.CreateAsync(It.IsAny<Wheels>())).ReturnsAsync(car);

var myClass = new ClassToTest(someService.Object);

【讨论】:

  • 使用起订量没有更好的选择吗?
  • 定义better。直接创建 POCO 总是更好。 Moq 的存在是为了创建接口和抽象类的实现,而不是具体的模型。
  • AutoFixture 库也是自动创建此数据的好方法,因为它会自动填充所需的对象(此处为Car),并为构造函数注入和使用合理的默认值属性注入。这避免了您需要手动构建如此复杂的对象的抱怨。我一直在使用它(和起订量)。
  • @JeffDammeyer 看,这正是我在我的项目中反对的那种东西 :) 因此它是基于意见的。他们的自述文件说It can create values of virtually any type without the need for you to explicitly define which values should be used。这意味着,例如,如果他们的库开始为 int 生成不同的值,您的测试可能只是因为您更新了该库而开始失败。这对调试开发人员来说是不透明的,并且难以阅读。
  • @zaitsman 很受欢迎,但请记住,这个库是完全可定制的,因此,在您的示例中,您可以准确定义如何创建 int,如果它确实对你在测试什么。当(对于您的测试)如何创建这样的依赖关系无关紧要时,您不要理会它。我只是为亲爱的提问者提供这个库,因为为此测试手动创建 POCO 是一个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-14
  • 1970-01-01
  • 2016-01-26
  • 1970-01-01
  • 2017-11-26
  • 2021-05-24
  • 1970-01-01
相关资源
最近更新 更多