C# 单元测试外部服务

C# 单元测试外部服务,c#,unit-testing,C#,Unit Testing,我想对使用外部依赖项的函数进行单元测试 方法如下: public string GetUrl(string records = "") { if (records.IsNullOrEmpty()) { records = Partner.Current["Records"]; } return string.Format( "http://{0}/{1}?pid={2}", recordsdomain,

我想对使用外部依赖项的函数进行单元测试

方法如下:

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 person = Service.GetPerson(Guid.Empty, "115763963", 1);
如何解决这个问题

更新


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

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

根据您选择的模拟框架,代码看起来会有所不同。使用最小起订量,它看起来像:

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
var person=new Mock();
person.SetupGet(p=>p.firstname).Returns(“Joe”);
person.SetupGet(p=>p.firstname).Returns(“Smith”);
//你的模拟人现在会返回名字进行测试
//您可以将其传递给构造函数

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

将成为

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;
    }
}
也许很粗糙,但如果您只需要该服务为您提供一些数据以供使用,那么应该可以继续使用。如果您还需要测试服务本身,那么这种方法显然是荒谬的

更新:由于
人员的ctor不可访问,要使此方法起作用,您也必须伪造它。。。需要立即检查的一件事是,如果
Person
是一个
partial
类,您可能可以在其中添加一个新的ctor(需要尝试,因为我做了类似的事情已经有一段时间了):

我使用这种方法来扩展自动生成的数据上下文类,它可能也适用于您


在不太严重的情况下,您还可以要求将公共ctor重载添加到该类中

为什么不能模拟服务?因为外部服务创建对象并从其数据库中提供对象。此外,该对象是在外部服务上声明的,因此我不能仅仅创建它的新实例并将信息提供给它。这听起来像是一个完美的例子,说明了什么时候应该使用mock,实际上,mock服务和mock方法调用它来为您返回一个人。(事实上见@fan711)下面的答案。此人有一个私人构造函数。我不想嘲笑它。这里是错误:“参数类型moq.Mock不可分配给参数类型”如果您的外部服务正在测试中,并且service.GetPerson已经测试过,您应该只模拟服务我刚刚注意到您说您不能moq它。为什么?我认为这个解决方案非常接近最佳答案。这里有一个错误:personsomething=newperson{/*在这里放好数据*/}***无法在此处访问受保护的构造函数“person”。你可能也得假装那个人,然后。。。我会更新答案。忽略它。不幸的是,人是抽象的。无法使用该方法…或者:(
public static class FakeService
{
    public static Person GetPerson(Guid foo, string bar, int baz)
    {
        Person something = new Person{ /*Put nice data here*/ };
        return something;
    }
}
public partial class Person
{
    public Person(){}
}