Можете ли вы выполнить модульное тестирование пустого метода, который не имеет возвращаемого типа? - PullRequest
1 голос
/ 07 июля 2019

У меня есть этот метод void, который я хотел бы протестировать, но, к сожалению, у меня нет большого опыта в этом.

public void findOccuranceMethod()
{
    string str = "The Haunting of Hill House!";
    Console.WriteLine("String: " + str);
    string occurString = "o";
    string replaceString = "MDDS";

    var array = str.Split(new[] { occurString }, StringSplitOptions.None);
    var count = array.Length - 1;
    string result = string.Join(replaceString, array);

    Console.WriteLine("String after replacing a character: " + result);
    Console.WriteLine("Number of replaces made: " + count);
    Console.ReadLine();

}

Вот TestClass, где я пытаюсь протестировать, но он сохраняетзагрузка при запуске:

[TestMethod()]
public void findOccuranceMethodTest()
{
    // Arrange
    string expected = "The Haunting MDDSf Hill HMDDSuse!";

    // Act
    var result = new findOccurance();

    // Assert
    Assert.AreEqual(expected, result);
}

Ответы [ 2 ]

4 голосов
/ 07 июля 2019

Код надлежащим образом переработан для проверки

Правильный способ кодирования и модульного тестирования такой логики будет:

public class SomeProductionClass 
{
    public string findOccuranceMethod(string str) 
    {
        string occurString = "o";
        string replaceString = "MDDS";
        var array = str.Split(new[] { occurString }, StringSplitOptions.None);
        string result = string.Join(replaceString, array);

        return result;
    }
}

[TestMethod()]
public void findOccuranceMethodTest()
{
    // Arrange
    string expected = "The Haunting MDDSf Hill HMDDSuse!";
    var productionClass = new SomeProductionClass();

    // Act
    var result = productionClass.findOccuranceMethod("The Haunting of Hill House!");

    // Assert
    Assert.AreEqual(expected, result);
}

Как проверить оригинальный код

Если по какой-то причине вы не можете контролировать производственный код, есть два варианта:

  • заменить Console на абстракцию

  • переназначить стандартный ввод / вывод для пользовательского потока: это наименее предпочтительный вариант, поскольку он усложняет настройку / очистку и может помешать исполнителю теста.

В любом случае мы никогда не должны изменять тестируемый код таким образом, чтобы вводить отдельные ветвления для тестирования / производства. Например, «если выполняется в тесте, сделайте A, в противном случае сделайте B» - в таком случае мы на самом деле не тестируем производственный код, а скорее его другую ветвь.

Заменить Консоль на абстракцию

Здесь мы вводим IConsole вместо System.Console:

public interface IConsole
{
    void WriteLine(string s);
    void ReadLine(); // void is enough for this example
}

// for use in production
public class RealConsole : IConsole
{
    public void WriteLine(string s)
    {
        Console.WriteLine(s); 
    }
    public void ReadLine()
    {
        Console.ReadLine();
    }
}

// for use in unit tests
public class TestConsole : IConsole
{
    public void WriteLine(string s)
    {
        Contents.Add(s);
    }
    public void ReadLine()
    {
    }

    public List<string> Contents { get; } = new List<string>();
}

Рабочий код останется таким же, как в исходном сообщении, за исключением того, что теперь он потребляет _console в качестве зависимости:

public class SomeProductionClass
{
    private readonly IConsole _console;

    public SomeProductionClass(IConsole console)
    {
        _console = console;
    }

    public void findOccuranceMethod()
    {
        string str = "The Haunting of Hill House!";
        _console.WriteLine("String: " + str);
        string occurString = "o";
        string replaceString = "MDDS";

        var array = str.Split(new[] { occurString }, StringSplitOptions.None);
        var count = array.Length - 1;
        string result = string.Join(replaceString, array);

        _console.WriteLine("String after replacing a character: " + result);
        _console.WriteLine("Number of replaces made: " + count);
        _console.ReadLine();
    }
}

и тестовый код будет:

[TestMethod()]
public void findOccuranceMethodTest()
{
    // Arrange
    string expectedString = "The Haunting MDDSf Hill HMDDSuse!";
    int expectedCount = 2;
    var console = new TestConsole();
    var productionClass = new SomeProductionClass(console);

    // Act
    productionClass.findOccuranceMethod();

    // Assert
    Assert.AreEqual(3, console.Contents.Count);
    Assert.AreEqual("String: The Haunting of Hill House!", console.Contents[0]);
    Assert.AreEqual(
        $"String after replacing a character: {expectedString}", 
        console.Contents[1]);
    Assert.AreEqual(
        $"Number of replaces made: {expectedCount}", 
        console.Contents[2]);
}
1 голос
/ 07 июля 2019

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

    public void optionSameSignature(Action<string> log = null, Func<string> read = null)
    {
        log = log ?? Console.WriteLine;
        read = read ?? Console.ReadLine;

        string str = "The Haunting of Hill House!";
        log("String: " + str);
        string occurString = "o";
        string replaceString = "MDDS";

        var array = str.Split(new[] { occurString }, StringSplitOptions.None);
        var count = array.Length - 1;
        string result = string.Join(replaceString, array);

        log("String after replacing a character: " + result);
        log("Number of replaces made: " + count);
        read();
    }

    public void Test()
    {
        List<string> lines = new List<string>();
        optionSameSignature(lines.Add, () => "");
    }

На более глубоком уровне ввод и вывод - это техническая деталь, поэтому в идеале вы должны попытаться получить ценность для своего бизнеса.Код без технических деталей.Примерно так может быть ближе к вашим реальным потребностям:

    private static void mybusinessfunction(string input, out int count, out string result)
    {
        string occurString = "o";
        string replaceString = "MDDS";

        var array = input.Split(new[] { occurString }, StringSplitOptions.None);
        count = array.Length - 1;
        result = string.Join(replaceString, array);
    }
...