Модульный тест класса, который содержит IDictionary - PullRequest
0 голосов
/ 14 января 2009

Я создаю класс, который определяет, какой из числа зарегистрированных обратных вызовов клиента WCF позвонить. Когда клиент регистрируется на сервере, он предоставляет интересующий его токен. Затем класс сохраняет отображение токена в интерфейс IClientCallback для этого токена в словаре.

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

public class Router
{
    private IDictionary<int, IClientCallBack> clients;

    public Router()
    {
        clients = new Dictionary<int, IClientCallBack>();
    }

    public Router(IDictionary<int, IClientCallBack> clients)
    {
        this.clients = clients;
    }

    public bool Register(int token, IClientCallBack client)
    {
        if (!clients.ContainsKey(token))
        {
            clients.Add(token, client);
            return true;
        }
        return false;
    }
}

Как проверить, что клиенты успешно зарегистрированы на маршрутизаторе? Я решил, что могу либо предположить, что если функция вернула true, то она успешна (но что делать, чтобы тело функции не возвращало только «return true;»?) Или я мог бы вставить словарь клиентов в конструктор класса и в мой проверить, что я могу проверить, что клиенты. Количество равно 1, как показано ниже.

[TestMethod]
public void RegisterTest()
{
    IDictionary<int, IClientCallBack> clients = new Dictionary<int, IClientCallBack>();
    var router = new Router(clients);
    var client = new Mock<IClientCallBack>().Object;
    var success = router.Register(4, client);
    Assert.IsTrue(success);
    Assert.AreEqual(1, clients.Count);
    Assert.AreEqual(clients[4], client);           
}

Несмотря на то, что приведенный выше тест кажется хорошим, кажется чрезмерным использование внедрения зависимостей для вставки коллекции, просто чтобы я мог проверить ее. Однако это делает тестирование намного проще и точнее (при тестировании и других методов класса).

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

Ответы [ 3 ]

2 голосов
/ 14 января 2009

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

Итак, если вы дважды вызываете Register для одного и того же токена, он должен вернуть false, верно? Сделайте это тестом. Предположительно, будут и другие вещи, связанные с токенами, поэтому проверьте, когда токены зарегистрированы, а когда нет.

Говоря так: если кто-то захочет переопределить класс, используя связанный список пар токен / клиент, это нарушит полезную функциональность класса? Я подозреваю, что нет - поэтому ваши тесты, вероятно, не должны волновать.

Теперь, прежде чем я начну звучать слишком академично, я не из тех людей, которые считают, что модульные тесты всегда должны касаться только общедоступных методов и не заботиться о реализации. Это не тесты черного ящика. Иногда знание реализации может значительно облегчить тестирование всего лишь одного сложного логического фрагмента, даже если он обычно выставлен с помощью чего-то, что на самом деле делает больше работы. Но в случае, который вы представили, я бы действительно придерживался подхода «делает ли он то, что должен, насколько может сказать внешний мир».

0 голосов
/ 14 января 2009

Хороший вопрос, Джон. Класс выше немного упрощен по сравнению с тем, что я пробовал на работе сегодня днем. В тестируемом коде я предоставил 1 или более токенов для регистрации IClientCallBack. Для каждого токена должна быть словарная запись. Идея в том, что Resolve (int token) вернет сопоставленный IClientCallBack ...

Что бросает меня, если мой метод

public bool Register(int token, IClientCallBack client)
{
    return true;
}

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

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

Возможно, я просто балую точку TDD:)

0 голосов
/ 14 января 2009

По сути, если вы смотрите на внутреннюю структуру данных, ваш тест проверяет конкретную реализацию, а не утверждает ожидаемое поведение класса.

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

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