Проверка модульного теста на наличие краевого случая - PullRequest
1 голос
/ 19 мая 2019

У меня есть функция для лучевого вещания на сетке с алгоритмом Брезенхэма.Я хочу оптимизировать для конкретных случаев, когда линия ортогональна или диагональна;конечно, эта логика не будет возвращена / выставлена ​​пользователю.

Можно ли обнаружить крайний случай оптимизации через модульное тестирование?Например, при вызове функции ищите определенный маркер Debug.WriteLine.

Я новичок в модульном тестировании, и, возможно, мне не хватает точки (тестирование функциональности предоставляется пользователю), но я утверждаю, что мои пограничные случаи работают какОжидаемый может быть неоценимым - особенно при активной разработке оптимизаций.

Пример того, чего я хочу достичь:

public IEnumerable<Coordinate> RayCast (Coordinate source, Coordinate direction) {
    if (direction.X == 0 || direction.Y == 0) {
        Debug.WriteLine ("Orthogonal_Edge_Case");
        //Simple iteration across 1 axis
        ...
        yield break;
    }
    if (Math.Abs(direction.X) == Math.Abs(direction.Y)) {
        Debug.WriteLine ("Diagonal_Edge_Case");
        //Simple diagonal iteration
        ...
        yield break;
    }        
    //Standard Bresenham's algorithm
    ...
    yield break;
}

...

[TestMethod]
public void TestRayCast () {
    var source = new Coordinate (0,0);

    var orthogonal = new Coordinate (0,1);
    CoordinateUtil.RayCast (source, orthogonal);
    //Check that the Orthogonal_Edge_Case marker was emitted

    var diagonal = new Coordinate (1,1);
    CoordinateUtil.RayCast (source, diagonal);
    //Check that the Diagonal_Edge_Case marker was emitted

    //Usual tests for RayCast
    ...
}

Примечание: IЯ использую тестовый набор Visual Studio 2019, но мне любопытно, возможно ли это с помощью любого инструмента .NET

Ответы [ 2 ]

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

У вас есть несколько вариантов:

  1. Удерживайте какое-то состояние, используя свойство в CoordinateUtil, которое позволит вам проверить, какой последний край был обнаружен.Это, однако, нарушит шаблон разделения ответственности Command Query Responsibility .
  2. Внедрение ILogger , которое позволит вам регистрировать некоторую информацию о синхронизации среди других вещей (очень похоже на option2, но с незначительным )другие настройки ).

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

public class CoordinateUtil
{
    private readonly IEdgeCaseDetector edgeCaseDetector;

    // This is the important bit where you inject an edge case detector
    public CoordinateUtil(IEdgeCaseDetector edgeCaseDetector)
    {
        this.edgeCaseDetector = edgeCaseDetector;
    }

    public IEnumerable<Coordinate> RayCast(Coordinate source, Coordinate direction)
    {
        if (direction.X == 0 || direction.Y == 0)
        {
            edgeCaseDetector.Detect("Orthogonal_Edge_Case");
            //Simple iteration across 1 axis
            yield break;
        }
        if (Math.Abs(direction.X) == Math.Abs(direction.Y))
        {
            edgeCaseDetector.Detect("Diagonal_Edge_Case");
            //Simple diagonal iteration
            yield break;
        }

        //Standard Bresenham's algorithm
        yield break;
    }
}

public interface IEdgeCaseDetector
{
    void Detect(string message);
}

public class EdgeCaseDetector
{
    public void Detect(string message)
    {
       // If you wanted to you could simply save the edge cases to a public property here
       // Or you might want to log them when you code runs outside of the unit test
    }
}

[TestClass]
public class CoordinateUtilTests
{
    [TestMethod]
    public void RayCast_WhenOthogonal_DetectsEdgeCase()
    {
        // Arrange
        var mock = new Mock<IEdgeCaseDetector>();
        var coordinateUtil = new CoordinateUtil(mock.Object);
        var source = new Coordinate(1, 1);

        // Act
        // Remember the ToArray because we need to evaluate the enumerable
        // before we can check if the edge case was detected.
        coordinateUtil.RayCast(source, new Coordinate(0, 0)).ToArray();

        // Assert
        mock.Verify(x => x.EdgeDetected("Orthogonal_Edge_Case"));
    }
}
0 голосов
/ 19 мая 2019

Экспонировать внутреннюю логику во внешнем мире только ради тестов - не лучший подход.
Вы должны тестировать только на предмет публичного API и поведения.
Для тестов производительности это может быть сложно, но выполнимо,Например, какое поведение получит потребитель тестируемого метода, если вы выполните стандартный алгоритм Брезенхэма для краевых случаев?

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

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

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