Moq Test - Mocked Service Call всегда возвращает NULL - PullRequest
1 голос
/ 10 февраля 2020

Я новичок в Moq и Mocks / Unit Testing в целом. После просмотра видео о Mocking, в котором используется Moq , я подумал, что у меня достаточно понимания, чтобы приступить к настройке нескольких простых тестов для проекта, над которым я работаю. Тем не менее, никакие манипуляции с кодом не помогут в моем первом прохождении теста.

Вот код, который у меня есть:

Тестируемый интерфейс

    public interface IDataInterface
    {
        Task<IList<T>> GetData<T>(string url);
        // Other stuff
    }

Реализация метода интерфейса GetData

        public async Task<IList<T>> GetData<T>(string url)
        {
            try
            {
                var json = await client.GetAsync(url).Result.Content.ReadAsStringAsync();
                var data = (JObject)JsonConvert.DeserializeObject(json);
                JArray arr = (JArray)data["resource"];
                return arr.ToObject<IList<T>>();
            }
            catch (InvalidCastException icEx)
            {
                throw new InvalidCastException("An error occurred when retrieving the data", icEx);
            }
            // Other catches
        }

Реализованный интерфейс службы вызова GetData

        public async Task<IList<MyObj>> GetActiveObjs()
        {
            var data = await _myImplementedInterface.GetData<MyObj>(ActiveUrl);
            return data;
        }

Мой тест

        [Fact]
        public async void MyImplementedInterface_GetActive_ReturnsDataOrEmptyList()
        {
            var _activeUrl = "http://some.url";
            using (var mock = AutoMock.GetLoose())
            {
                mock.Mock<IDataInterface>()
                    .Setup(x => x.GetData<MyObj>(_activeUrl))
                    .Returns(Task.FromResult(_SomeStaticDataRepresentation)));

                var svc = mock.Create<MyService>();

                var expected = _SomeStaticDataRepresentation;
                var actual = await svc.GetActiveObjs();

                Assert.True(actual != null);
                // Other assertions that never matter because of the null value of _actual_ variable
            }
        }

Вначале у меня были проблемы, потому что в проекте используются Autofa c и Moq, но я решил эти конкретные c проблемы. Тем не менее, я не могу проигнорировать нулевое значение, возвращаемое после вызова службы. При запуске проекта метод возвращает данные, как и ожидалось, поэтому я не уверен, где находится проблема. Просмотр различных постов и Moq Quickstart не позволили мне решить эту проблему самостоятельно, поэтому я надеюсь, что здесь найдется кто-то, кто скажет мне, что я делаю неправильно. Я уже извиняюсь, так как уверен, что это новая ошибка ie.

1 Ответ

3 голосов
/ 10 февраля 2020

Сначала обращаемся к реализации. Избегайте смешивания асинхронных c -wait и блокирующих вызовов, таких как Wait() и .Result, которые могут привести к взаимоблокировкам.

Ссылка Асинхронное / ожидание - Рекомендации по асинхронному программированию

public async Task<IList<T>> GetData<T>(string url) {
    try {
        var response = await client.GetAsync(url);
        var json = await response.Content.ReadAsStringAsync();
        var data = (JObject)JsonConvert.DeserializeObject(json);
        JArray arr = (JArray)data["resource"];
        return arr.ToObject<IList<T>>();
    } catch (InvalidCastException icEx) {
        throw new InvalidCastException("An error occurred when retrieving the data", icEx);
    }
    // Other catches
}

Для тестируемого метода-субъекта, если ничего не нужно ожидать, то нет необходимости делать функцию асинхронной c, просто верните Task

public Task<IList<MyObj>> GetActiveObjs() {
    return _myImplementedInterface.GetData<MyObj>(ActiveUrl);
}

Теперь для тест, поскольку уже используются задачи, тогда тест должен быть асинхронным c и субъект также должен быть ожидаемым.

[Fact]
public async Task MyImplementedInterface_GetActive_ReturnsDataOrEmptyList() {
    using (var mock = AutoMock.GetLoose()) {
        //Arrange
        IList<MyObj> expected = _SomeStaticDataRepresentation;
        mock.Mock<IDataInterface>()
            .Setup(x => x.GetData<MyObj>(It.IsAny<string>()))
            .ReturnAsync(expected);

        var svc = mock.Create<MyService>();

        //Act
        var actual = await svc.GetActiveObjs();

        //Assert
        Assert.True(actual != null);
        Assert.True(actual == expected);
        // ...
    }
}

Предполагая, что, исходя из показанного, неясно, каким был бы активный URL , это можно игнорировать в тесте, используя It.IsAny<string>().

...