Как я смогу провести модульное тестирование пустого метода? - PullRequest
0 голосов
/ 30 мая 2019

Я хочу проверить мой метод, который проверяет направление движения транспортных средств. Это пустой метод и имеет один параметр - целое число.

Насколько я знаю, все if должны быть разделены на разные методы тестирования, но я не знаю, как это сделать.

/// <summary>
        /// checks the east neighbour of the crossing on a given cell
        /// </summary>
        /// <param name="cellNr">the cell Nr of the crossing whose neighbour ///its checked</param>

    public void CheckEast(int cellNr)
    {
        Crossing cr = Cells[cellNr].Crossing;

        //If there is east neighbour - laneIns of the current crossing with direction east are NOT endLane
        if (cells[cellNr + 1].Taken)
        {
            foreach (LaneIn laneIn in cr.LaneInList)
            {
                if (laneIn.Direction == "west")
                {
                    laneIn.EndLane = false;
                }
            }

            //car should NOT be spawned from east && LaneOut of current crossing with direction east is NOT endLane
            cr.IncomingStreams[3] = "";
            cr.LaneOutList[0].EndLane = false;

            //LaneIn 'east' of the east neighbour is NOT endLane
            foreach (LaneIn laneIn in cells[cellNr + 1].Crossing.LaneInList)
            {
                if (laneIn.Direction == "east")
                {
                    laneIn.EndLane = false;
                }
            }
            //no spawned car in the neighbour from the east laneIns and LaneOut 'west' is not endlane
            cells[cellNr + 1].Crossing.IncomingStreams[1] = "";
            cells[cellNr + 1].Crossing.LaneOutList[1].EndLane = false;
            cr.Neighbours[1] = cells[cellNr + 1].Crossing;
            cells[cellNr + 1].Crossing.Neighbours[3] = cr;
        }
        //if there is NO neighbour on east side, laneIns of the current crossing are endlane(spawning point)
        //laneout is endlane, cars are erased after leaving it
        else
        {
            cr.Neighbours[1] = null;
            cr.IncomingStreams[3] = "west";
            cr.LaneOutList[0].EndLane = true;
            foreach (LaneIn laneIn in cr.LaneInList)
            {
                if (laneIn.Direction == "west")
                {
                    laneIn.EndLane = true;
                }
            }
        }
    }

Ответы [ 2 ]

2 голосов
/ 30 мая 2019

Чтобы буквально ответить на ваш вопрос, если метод не имеет возвращаемого значения, он должен вызвать какой-то другой побочный эффект.(Если он ничего не возвращает или не имеет побочного эффекта, он ничего не делает.)

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

public class Counter
{
    public int Value { get; private set; }

    public void Increment() => Value++;
}
public void Counter_increments()
{
    var subject = new Counter();
    subject.Increment();
    Assert.AreEqual(1, subject.Value());
}

Или, возможно, поведение, которое вы хотите проверить, - это взаимодействие вашего класса с некоторой зависимостью.Есть несколько способов сделать это.Одним из них является проверка состояния зависимости:

public class ClassThatIncrementsCounter
{
    public readonly Counter _counter;

    public ClassThatIncrementsCounter(Counter counter)
    {
        _counter = counter;
    }

    public void DoSomething()
    {
        // does something and then increments the counter
        _counter.Increment();
    }
}

[TestMethod]
public void DoSomething_increments_counter()
{
    var counter = new Counter();
    var subject = new ClassThatIncrementsCounter(counter);
    subject.DoSomething();
    Assert.AreEqual(1, counter.Value);
}

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

public class ClassThatIncrementsCounter
{
    public readonly ICounter _counter;

    public ClassThatIncrementsCounter(ICounter counter)
    {
        _counter = counter;
    }

    public void DoSomething()
    {
        // does something and then increments the counter
        _counter.Increment();
    }
}

[TestMethod]
public void DoSomething_increments_counter()
{
    var counter = new Mock<ICounter>();

    // indicate that we want to track whether this method was called.
    counter.Setup(x => x.Increment()).Verifiable();
    var subject = new ClassThatIncrementsCounter(counter.Object);
    subject.DoSomething();

    // verify that the method was called.
    counter.Verify(x => x.Increment());
}

Чтобы это работало хорошо, как вы заметили, необходимо разбить методы на более мелкие блоки, которые мы можем тестировать изолированно.Если метод принимает множество решений, то для полного тестирования нам нужно протестировать каждую подходящую комбинацию или каждую возможную ветвь, по которой может выполняться код.Вот почему метод с множеством условий может быть сложнее протестировать.

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

Вы можете взять большие куски кода, которые повторяются следующим образом:

        foreach (LaneIn laneIn in cr.LaneInList)
        {
            if (laneIn.Direction == "west")
            {
                laneIn.EndLane = false;
            }
        }

        foreach (LaneIn laneIn in cr.LaneInList)
        {
            if (laneIn.Direction == "west")
            {
                laneIn.EndLane = true;
            }
        }

... и заменить их такими методами, за исключением того, что вы дадите им ясный, значимыйимена.Я не могу этого сделать, так как я не уверен, что они делают:

public void SetEndLaneInDirection(List<LaneIn> laneInList, string direction, bool isEnd)
{
    foreach (LaneIn laneIn in laneInList)
    {
        if (laneIn.Direction == direction)
        {
            laneIn.EndLane = isEnd;
        }
    }
}

Теперь, когда один меньший фрагмент кода легче тестировать.Или, если у вас есть блок методов, которые все производят какое-то связанное обновление, подобное этому:

        cells[cellNr + 1].Crossing.IncomingStreams[1] = "";
        cells[cellNr + 1].Crossing.LaneOutList[1].EndLane = false;
        cr.Neighbours[1] = cells[cellNr + 1].Crossing;
        cells[cellNr + 1].Crossing.Neighbours[3] = cr;

Затем поместите их в метод и снова дайте ему четкое имя.

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

Побочным эффектом является то, что при замене фрагментов кода вызовами методов с именами, ваш код становится легчепрочитайте, потому что вызовы метода говорят почти на английском языке, что делает каждый шаг.

После факта сделать это намного сложнее.Часть проблемы - научиться писать код, который уже легче тестировать.Хорошая новость заключается в том, что, как мы делаем, наш код, естественно, становится проще и легче следовать.И у нас есть тесты.

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

1 голос
/ 30 мая 2019

В своем модульном тесте вы вызываете CheckEast с cellNr, установленным на некоторые значения, а затем утверждаете, что ожидаемые побочные эффекты (то есть изменения) были сделаны для Cells, LaneInList и т. Д. ., структуры данных.

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