我想对一个消耗外部依赖的函数进行单元测试。
这是方法:
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对象并从其数据库中提取对象。此外,该对象在外部服务上声明,因此我不能只创建它的新实例并将信息提供给它。
答案 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重载添加到该类中!