在没有setter的情况下模拟具体对象属性

时间:2014-03-05 13:53:49

标签: c# unit-testing moq

我正在测试与第三方系统连接的服务。 API公开的方法返回如下所示的对象:

public class Thing
{
    public string Name { get {...} }
    public string Description { get {...} }

    public Thing(string someUri)
    {
        /* Do some secret internal stuff and
           populate all my properties. */
    }
}

我需要模拟这些属性,以便根据返回的对象测试我的服务是否正常运行。

对象是具体类的实例,它不实现我可以模拟的任何接口。这些属性的支持字段在Thing的构造函数中设置,它接受一个URI,关闭并在一个紧密耦合的第三方系统中获取对象,并且可能直接设置后备字段。

所有这些意味着我无法模拟属性 - 我无法直接设置它们,我无法模拟接口,我无法模拟构造函数依赖项并以这种方式设置属性(无论如何都会削弱我测试的实用性。)

有什么方法吗?

3 个答案:

答案 0 :(得分:1)

您可以使用Shims(构建到visual studio中)伪造Thing

http://msdn.microsoft.com/en-us/library/hh549175.aspx

答案 1 :(得分:1)

假设您在Premium或Ultimate Edition中使用VS2012.2或VS2013,shims应该可以满足您的需求。他们允许" shimming"属性和构造函数,理想情况下仅适用于您自己所在的场景(不使用接口的第三方库)。

在您的单元测试项目中为您的库添加Fakes程序集后,您在单元测试中执行以下操作:

using (ShimsContext.Create())
{
    ShimThing.ConstructorString = (@this, value) => {
        var shim = new ShimThing(@this) {
            NameGet = () => "Your Desired Name",
            DescriptionGet = () => "Your Desired Description"
        };
    };

    //do whatever you need to do that creates a Thing object
}

我在没有实际尝试的情况下编写了这个示例,因此ShimThing构造函数的语法可能略有偏差。

答案 2 :(得分:1)

你可以把Thing包裹起来 - 这可能不是你正在寻找的答案,因为它将涉及对应用程序代码的更改以支持你的单元测试,但它会导致更松散耦合的代码库和从长远来看,可能会让你的生活更轻松。

创建一个ThingWrapper类,它将Thing作为构造函数参数,其属性在包装的Thing实例上调用getter。那么你可以

  • 将这些属性标记为virtual并直接模拟包装器(代码较少)
  • 或让包装器实现针对该接口的接口代码(可能更好)。

希望这会有所帮助,对不起,如果我只是陈述显而易见的事:/