创建对象的新实例时,如何将服务注入构造函数?

时间:2018-06-29 16:09:03

标签: unit-testing asp.net-core dependency-injection asp.net-core-mvc asp.net-core-2.0

安装程序:我已经注册了一个配置服务,该服务从appsettings.json中提取数据,并且运行正常。我还有一个控制器使用该服务从该文件中获取设置,同样,它的工作方式也应该像这样:

public class ApiController : Controller
{
    private readonly string _apiUri;
    public ApiController(IOptions<Configurator> config)
    {
        _apiUri = config.Value.ApiSettings.ApiBaseUrl + 
                  config.Value.ApiSettings.ApiVersion;
    }
    //...
}

现在注意,我是自动化单元测试和asp.net核心的新手。我想做的是消除ApiController对注入服务的依赖,以便我可以使用单独的XUnit测试项目来测试控制器内部的功能,类似于this tutorial中的示例。

为此,我创建了一个模型和接口来表示我的appsettings.json文件的ApiSettings部分:

"ApiSettings": {
    "ApiBaseUrl": "https://example.com/api/",
    "ApiVersion": "v1/"
}

模型:

public class ApiSettings : IApiSettings
{
    public string ApiBaseUri { get; set; }
    public string ApiVersion { get; set; }
}

界面:

public interface IApiSettings
{
    string ApiBaseUri { get; set; }
    string ApiVersion { get; set; }
}

然后我创建了一个依赖于服务来注入设置的类:

public class ApiSettingsBuilder
{
    private readonly string _apiUri;
    public ApiSettingsBuilder(IOptions<Configurator> config)
    {
        _apiUri = config.Value.ApiSettings.ApiBaseUrl + 
                  config.Value.ApiSettings.ApiVersion;
    }

    public string ApiUri { get { return _apiUri; } }
}

问题:如何创建此类的新实例?

public class ApiController : Controller
{
    private readonly string _apiUri;
    public ApiController()
    {
        ApiSettingsBuilder builder = new ApiSettingsBuilder(/*What do I do here*/);
        _apiUri = builder.ApiUri;
    }

    public ApiController(IApiSettings settings)
    {
        //For testing
        _apiUri = settings.ApiBaseUrl + settings.ApiVersion;
    }
    //...
} 

此外,我知道这都有些过分,但我仍想得到一个答案,因为它在其他情况下可能很有用。

1 个答案:

答案 0 :(得分:3)

您不必出于单元测试的目的而创建新的类,可以使用适当的框架(例如,最小起订量:

var configurator = new Configurator() { ApiBaseUrl = "abc" };
var mock = new Mock<IOptions<Configurator>>();
mock.Setup(ap => ap.Value).Returns(configurator);

然后,您可以将模拟对象传递给构造函数以进行单元测试:

var controller = new ApiController(mock.Object);