Дразнить метод с действием <T> - PullRequest
0 голосов
/ 29 мая 2018

Я новичок в модульном тестировании, был бы рад узнать, если я делаю какую-либо ошибку или не иду в правильном направлении.

Вот ситуация:

Я пытаюсь проверитьметод (MethodUnderTest), который вызывает другой метод (MethodWithAction), который принимает Action<T> в качестве аргумента.Я хочу смоделировать MethodWithAction, но проверить логику на основе возвращаемого значения.

Вот структура:

interface IInterface
{
    void MethodWithAction(Action<string> action);
}

class MyClass : IInterface
{
    public void MethodWithAction(Action<string> action)
    {
        string sampleString = "Hello there";
        action(sampleString);
    }
}

class ClassUnderTest
{
    public IInterface Obj = new MyClass();
    public string MethodUnderTest()
    {
        string stringToBeTested = string.Empty;

        Obj.MethodWithAction(str =>
        {
            if (str.Contains("."))
                stringToBeTested = string.Empty;
            else
                stringToBeTested = str.Replace(" ", string.Empty);
        });
        return stringToBeTested;
    }
}

Мой метод тестирования выглядит следующим образом:

[TestMethod]
[DataRow("Hello, World", "Hello,World")]
[DataRow("Hello, World.","")]
[DataRow("Hello", "Hello")]
public void MethodUnderTestReturnsCorrectString(string sampleString, string expected)
{
    var mockObj = new Mock<IInterface>();
    mockObj.Setup(m=>m.MethodWithAction(It.IsAny<Action<string>>))
    .Callback(???);
    ClassUnderTest sut = new ClassUnderTest();
    sut.Obj=mockObj.Object;
    string actual = sut.MethodUnderTest();
    Assert.Equal(expected, actual);
 }

Хотелось бы узнать, что происходит на месте ??? в тесте, или есть совершенно другой подход к этой проблеме?

Ответы [ 2 ]

0 голосов
/ 29 мая 2018

Моим первым инстинктом было бы рефакторинг ClassUnderTest и IInterface, чтобы у IInterface было свойство get, такое, что вы полностью удаляете зависимость реализации IInterface, а MyClass выполняет только одну работу (сохраняйте SampleString):

interface IInterface
{
    string SampleString { get; }
}

// Fix MyClass
class MyClass : IInterface
{
    public string SampleString => "Hello There"
}

class ClassUnderTest
{
    public string MethodUnderTest(IInterface someObject)
    {
        string stringToBeTested = string.Empty;

        if (someObject.SampleString.Contains("."))
            stringToBeTested = string.Empty;
        else
            stringToBeTested = str.Replace(" ", string.Empty);

        return stringToBeTested;
    }
}

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

Еще один способ взглянуть на проблему.

0 голосов
/ 29 мая 2018

Захватите параметр действия, который был передан макету при обратном вызове, и вызовите его со строкой образца.

mockObj
    .Setup(m => m.MethodWithAction(It.IsAny<Action<string>>))
    .Callback((Action<string> action) => action(sampleString));

Ссылка Быстрый запуск Moq , чтобы лучше понять, какиспользовать эту насмешливую основу.

...