Определение основного контейнера .NET для тестового проекта NUnit - PullRequest
0 голосов
/ 08 ноября 2018

Я новичок в .NET Core. Я хочу знать, как я могу определить DI-контейнер в проекте библиотеки классов NUnit. Я знаю, что это делается через IServiceCollection, но, поскольку нет метода запуска, я не знаю, где взять экземпляр, реализующий этот интерфейс.

Также я хотел бы иметь возможность загружать определения из других библиотек классов (являющихся предметом тестирования). Это должно быть проще, поскольку я могу просто создать статический метод в этой библиотеке классов с одним параметром IServiceCollection, но опять же, как мне его получить?

Дополнительный вопрос: я предполагаю, что некоторые интерфейсы могут быть смоделированы для целей тестов, но я не понимаю, как я могу заменить отображение, уже созданное с использованием методов IServiceCollection, таких как AddSingleton или AddTransient. Существует метод Remove, но он не задокументирован.

Спасибо, Радек

Ответы [ 2 ]

0 голосов
/ 10 ноября 2018

IServiceCollection реализуется классом ServiceCollecion. Поэтому, если вы хотите сделать это для интеграционных тестов, вы можете использовать класс ServiceCollection, чтобы создать свой собственный ServiceProvider.

var services = new ServiceCollection();

services.AddTransient<IMyInterface, MyClass>();
services.AddScoped<IMyScopedInteface, MyScopedClass>();
...

var serviceProvider = sc.BuildServiceProvider();

Теперь вы можете использовать экземпляр serviceProvider в своих тестах для получения классов:

var myClass = serviceProvider.GetService<IMyInterface>();

Если вы хотите смоделировать некоторые интерфейсы вместо использования реальных, то вместо добавления реального класса / интерфейса в коллекцию сервисов вы можете вместо этого добавить макет:

mockInterface = new Mock<IMyInterface>();

sc.AddScoped<IMyInterface>(factory => mockInterface.Object);
0 голосов
/ 09 ноября 2018

Как правило, вы не хотите создавать DI-контейнер для своих тестов, но, как вы понимаете, вместо этого вы хотите имитировать их. Так, например, если это класс, который вы хотите проверить:

public class UserService
{
    private readonly IUserDatabase _userDatabase;

    public UserService(IUserDatabase userDatabase)
    {
        _userDatabase = userDatabase;
    }

    public bool DoesUserExist(int userId)
    {
        return _userDatabase.UserExists(userId);
    }
}

И это определение используемого интерфейса:

public interface IUserDatabase
{
    bool UserExists(int userId);
}

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

[TestClass]
public class UserServiceTests
{
    [TestMethod]
    public void DoesUserExist_ForValidUserId_ReturnsTrue()
    {
        var fakeUserId = 123;

        var mockUserDatabase = new Mock<IUserDatabase>();
        mockUserDatabase.Setup(udb => udb.UserExists(fakeUserId)).Returns(true);

        var userService = new UserService(mockUserDatabase.Object);

        var result = userService.DoesUserExist(fakeUserId);

        Assert.IsTrue(result);
        mockUserDatabase.VerifyAll();
    }
}

Итак, в этом тесте мы использовали Moq для создания макета нашего интерфейса. Нам не нужно использовать DI-контейнер, потому что мы находимся в контроллере создания класса, который мы тестируем. Контейнер DI более широко используется в производстве, поскольку он позволяет приложению создавать любые необходимые ему зависимости без вызова кода new - что является большой проблемой, если вы пытаетесь выполнить модульное тестирование своих классов.

Метод .VerifyAll() проверяет, действительно ли были вызваны любые методы, настроенные для фиктивного объекта, в данном случае мы устанавливаем вызов UserExists.

Существует множество примеров того, как использовать Moq и интерфейсы для насмешек в целом. Краткое руководство по Moq здесь здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...