Как внедрить сервис в конструктор при создании нового экземпляра объекта? - PullRequest
0 голосов
/ 29 июня 2018

Настройка: Я зарегистрировал службу конфигурации, которая извлекает данные из 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 для тестирования функций внутри контроллера, аналогично примеру в этом учебном пособии .

Для этого я создал модель и интерфейс, представляющие раздел ApiSettings моего файла appsettings.json:

"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 голосов
/ 29 июня 2018

Вам не нужно создавать новые классы для целей модульного тестирования, вы можете смоделировать интерфейс ваших IOptions, используя соответствующую инфраструктуру, например, Moq:

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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...