Как использовать params при вызове mocked-метода в «реальном» методе? - PullRequest
0 голосов
/ 31 августа 2018

Я издеваюсь над методом с такой подписью:

public async Task<string> Upsert(Preferences prefs, string id)

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

Как передать параметры, отправленные в метод mocked, в «реальный» метод, как если бы я использовал лямбда-выражение?


Вызов лямбда-выражения (параметры совпадают с отправленными при вызове)

То есть, если бы я так писал с лямбдой ...

_mockDataAdapater
    .Setup(x => x.Upsert(It.IsAny<Preferences>(), It.IsAny<string>()))
    .Returns((Preferences p, string id) =>
    {
        return Task.FromResult(id);    
        // see how I can use  ^^^^  the `id` param here?
    });

... Я получаю возвращенное значение в параметре id при вызове.

public async void testMe()
{
    var output  = await _mockDataAdapater.Object.Upsert(new Preferences(), "hello");

    System.Diagnostics.Debug.WriteLine(output);    // <<< "hello" in this case.
}

Вот чего я хочу.

Вызов «реальной» функции (всегда «спам»)

Как мне не задавать значения параметров p & id при настройке и по-прежнему использовать этот синтаксис?

// This is what I want to use instead of a lambda expression.
private async Task<string> _upsertMock(Preferences prefs, string id)
{
    return await Task.Run(() =>
    {
        return id;
    });
}

//...

public MyClassConstructor()
{
    // Set up mock objects...

    _mockDataAdapater
        .Setup(x => x.Upsert(It.IsAny<Preferences>(), It.IsAny<string>()))
        .Returns(_upsertMock(new Preferences(), "spam")); 
        // Both params are hard coded! ^^^^^^^^^^^^^ 
        // 
        // (Rather, if I don't insert hard-coded params here, I can't
        //  get things to build. How do I hook up to the It.IsAnys?)
} 

всегда возвращает «спам» в вызове testMe. Bad Moq!

public async void testMe()
{
    var output  = await _mockDataAdapater.Object.Upsert(new Preferences(), "hello");

    System.Diagnostics.Debug.WriteLine(output);    // <<< now always "spam"
}

Чтобы было ясно, я знаю, почему я всегда получаю "spam". В этом есть смысл. Но воняет.

У меня вопрос, как вернуться к использованию параметров в "реальном" вызове метода во втором случае?


Это работает, но чувствует себя не так

Я могу обернуть свою функцию в другую функцию ...

_mockDataAdapater
    .Setup(x => x.Upsert(It.IsAny<Preferences>(), It.IsAny<string>()))
    .Returns((Preferences p, string id) =>
    {
        return _upsertMock(p, id);
    });

Является ли обертка единственным способом, которым я могу получить доступ к p и id?

1 Ответ

0 голосов
/ 31 августа 2018

Я попробовал следующее доказательство, и оно сработало, как и ожидалось

[TestClass]
public class MyTestClass {
    public class Preferences {

    }
    public interface IInterface {
        Task<string> Upsert(Preferences prefs, string id);
    }

    public Task<string> _upsertMock(Preferences prefs, string id) {
        return Task.Run(() => {
            return id;
        });
    }

    [Test]
    public async Task MyTestMethod() {

        var mock = new Mock<IInterface>();
        mock
            .Setup(_ => _.Upsert(It.IsAny<Preferences>(), It.IsAny<string>()))
            .Returns((Func<Preferences, string, Task<string>>)_upsertMock);

        var expected = "123";

        var actual = await mock.Object.Upsert(null, expected);

        actual.Should().Be(expected);
    }
}

Обратите внимание на кастинг делегата

.Returns((Func<Preferences, string, Task<string>>)_upsertMock);

, чтобы во время настройки использовалась правильная перегрузка .Returns.

...