使用专用设置器存根属性以进行测试


10

我们有对象

public class MyObject{
    protected MyObject(){}

    public string Property1 {get;private set;}
    public string Property2 {get;private set;}
    public string Property3 {get;private set;}
    public string Property4 {get;private set;}
    public string Property5 {get;private set;}
    public string Property6 {get;private set;}
    public string Property7 {get;private set;}
    public string Property8 {get;private set;}
    public string Property9 {get;private set;}
    public string Property10 {get;private set;}
}

在生产代码中,我们通过自动映射器填充此对象。它可以访问属性并正确设置它们。

现在,当我们想在将来的管道中测试此类时,就不可能用伪值(要进行测试)填充属性。

有一些可用的选项。

  • 自定义构造函数接受测试所需的参数并设置属性,目前需要3个构造函数。这是不干净的,因为构造函数不提供任何业务功能。

  • 将属性设置为虚拟,以便可以对类进行存根。但是将属性标记为虚拟不会提供任何商业价值,并且不会污染我的班级。

  • 将一个对象生成器添加到该类以内部构造该对象。再次没有增加业务价值。也许稍微干净一点,但领域对象中仍然有很多无关的代码。

有什么建议,建议或其他选择吗?

Answers:


8

您有很多选择。

  • 继续并使用自定义构造函数,虚拟属性或对象构建器。其背后的理由是,对象应该独立存在,而不要依赖自动映射器之类的魔术。除非发生一些不可思议的事情,否则一个完全没用的课程并不是对课程的很好的考虑。“业务价值”不是好的设计的唯一决定因素。

  • 在测试过程中包括自动映射器。有人会说这不再是单元测试了。不要紧。单元测试不是唯一的测试。

  • 实现某些东西,该东西提供了专门用于测试的automapper功能。您可以轻松编写一个小工具,该工具将使用反射从包含属性名称和值的字典中填充对象。

还要看一下这个问题和答案:您是希望将私有内容内部/公开进行测试,还是使用诸如PrivateObject之类的黑客工具?


3

在测试中,我会毫不犹豫地对此类事情使用反射。

我不喜欢将事物虚拟化为模拟对象,因为它会以错误的原因更改代码。

我不知道automapper,但我同意@Mike的观点,认为将其包含在测试中可能是个好主意。区分单元测试/集成测试不是非常有趣的imo。确保测试套件变大和变慢,您将需要对事物进行过滤和分类,以便仅以最高频率运行所有测试的合理子集。

使用反射的示例hack,使用nameof()将具有更好的性能,但随后您会松开类型。

public static class TestExtensions
{
    public static void SetProperty<TSource, TProperty>(
        this TSource source,
        Expression<Func<TSource, TProperty>> prop,
        TProperty value)
    {
        var propertyInfo = (PropertyInfo)((MemberExpression)prop.Body).Member;
        propertyInfo.SetValue(source, value);
    }
}

0

为了进行单元测试,请使用诸如Microsoft Fakes,TypeMock和JustMock之类的模拟框架,该框架为模拟私有成员提供支持。

请同时查看Smocks(可用的@nuget软件包)。Smocks的限制是,它将不提供对私人成员的访问。但是它具有模拟静态和非虚拟成员的能力。也可以免费使用。

另一个最简单的方法是使用PrivateObject / PrivateType。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.