单元测试外部服务

时间:2014-03-11 16:15:30

标签: c# unit-testing

我想对一个消耗外部依赖的函数进行单元测试。

这是方法:

public string GetUrl(string records = "")
{
    if (records.IsNullOrEmpty())
    {
        records = Partner.Current["Records"];
    }

    return string.Format(
        "http://{0}/{1}?pid={2}",
        recordsdomain,
        HttpUtility.UrlEncode(FullName
            .Replace(' ', '_')
            .Replace("\\", string.Empty)
            .Replace("?", string.Empty)),
        Id);
}

这个方法位于一个具有构造函数的类中,如下所示:

public Person(Person person)
{
      FullName = person.firstname + person.lastname
}

问题是: Person没有公共构造函数,这就是为什么它不允许为它创建模拟。

以下是人物对象的生成方式:

Person person = Service.GetPerson(Guid.Empty, "115763963", 1);

如何解决这个问题?

更新

外部服务创建person对象并从其数据库中提取对象。此外,该对象在外部服务上声明,因此我不能只创建它的新实例并将信息提供给它。

2 个答案:

答案 0 :(得分:1)

您需要使用模拟技术。您将创建一个mock person对象,该对象在firstname和lastname属性上返回固定值。然后,您可以将模拟人员传递给构造函数。

根据您选择的模拟框架,代码看起来会有所不同。使用Moq看起来像是:

var person = new Mock<Person>(); 
person.SetupGet(p => p.firstname).Returns("Joe");
person.SetupGet(p => p.firstname).Returns("Smith");
// your mock person does now return names for testing
// and you can pass it to the constructor

答案 1 :(得分:1)

如果可以认为外部服务功能是理所当然的,你总是可以伪造它(有点负担但如果你只需要数据来测试其他代码吧可能是可行的。)

Person person = Service.GetPerson(Guid.Empty, "115763963", 1);

会变成

Person person = FakeService.GetPerson(Guid.Empty, "115763963", 1);

你有类似

的地方
public static class FakeService
{
    public static Person GetPerson(Guid foo, string bar, int baz)
    {
        Person something = new Person{ /*Put nice data here*/ };
        return something;
    }
}

也许很粗糙,但如果你只需要服务为你提供一些数据就可以让你去,也就是说。如果您还需要测试服务本身,这种方法显然是荒谬的

更新:由于Person的ctor无法访问,因此这种工作方式你也不得不假装......如果Person是{ partial上课你可以把它拉下来,只需添加一个新的ctor(需要尝试,有一段时间,因为我做了类似的事情):

public partial class Person
{
    public Person(){}
}

我使用这种方法来扩展自动生成的数据上下文类,它也可能对你有用。

在一个不太严肃的说明中,您还可以要求将公共ctor重载添加到该类中!