Как я должен проверить публичный метод, который получает доступ к частному члену - PullRequest
3 голосов
/ 03 июня 2011

Так что у меня есть что-то вроде этого

private List<ConcurrentQueue<int>> listOfQueues = new List<ConcurrentQueue<int>>()
public void InsertInt(int id, int value)
{
    listOfQueues[id].Enqueue(value);
}

Это то, что мне не стоит тестировать?
Если это так, как я могу проверить метод InsertInt без использования каких-либо других методов? Можно ли использовать метод для извлечения данных из очереди, чтобы проверить правильность ввода? Это то, что я должен использовать насмешки для?

Ответы [ 6 ]

2 голосов
/ 03 июня 2011

Вы, как правило, не хотите тестировать частных пользователей.Суть модульного тестирования заключается в том, что извне класс принимает указанные входные данные и (по запросу) выдаст правильные выходные данные.Вы не заботитесь о реализации того, КАК он дает вам эти выходы, вы просто заботитесь о том, чтобы он дал вам правильные выходы для внешнего использования.

Чтобы показать это, скажем, вы создали модульный тест, который проверяет, что ваш метод InsertInt() вставляет int в listOfQueues.Затем ваши требования меняются, и вам приходится менять стратегию реализации, и вместо использования List<ConcurrentQueue<int>> он становится Dictionary<string, ConcurrentQueue<int>>.Это может на самом деле не требовать изменения ваших входов, и ваши выходы могут пройти любую проверку выходов, но ваш InsertInt() модульный тест не пройдёт, потому что он жестко запрограммирован для реализации.

Лучше сделатьмодульные тесты, которые гарантируют, что если вы вызовете InsertInt() с правильным вводом, ваши методы вывода по-прежнему будут возвращать исправленный вывод, а также создадут модульные тесты, в которых вызов InsertInt() с недопустимыми параметрами вызовет исключения.Затем вы можете изменить все в своей внутренней реализации и быть уверенным, что ваш класс по-прежнему работает правильно.Модульное тестирование реализации добавляет дополнительные накладные расходы, в то же время обеспечивая очень небольшое преимущество в тестируемости.

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

2 голосов
/ 03 июня 2011

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

Ознакомьтесь с этой статьей о том, как выполнить модульное тестирование частных методов http://msdn.microsoft.com/en-us/library/ms184807(v=vs.80).aspx

1 голос
/ 03 июня 2011

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

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

public int GetInt(int id)

. Затем вы проверяете, что метод вставляет, как вы ожидаете, извлекая их с использованием того же идентификатора.

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

        [TestCase(1,2,3)] // whatever test cases make sense for you
        [TestCase(4,5,6)]
        [TestCase(7,8,9)]
        [Test]
        public void Test_InsertInt_OK( int testId, int testValue, int expectedValue)
        {
            InsertInt(testId, testValue);
            Assert.AreEqual( GetInt(testId), expectedValue )
        }
1 голос
/ 03 июня 2011

Поскольку этот метод является общедоступным, его необходимо подвергнуть модульному тестированию.

Быстрый просмотр вашего метода показал бы, что передача -1 в качестве значения id вызовет ArgumentOutOfRangeException.Это было бы реализовано во время кодирования, если бы был разработан пример модульного теста для этого метода (при условии, что существует много таких методов).

Чтобы проверить, успешна ли вставка, вы можете использовать метод, указанный @Оскар Кьеллин.

Если вы хотите испачкаться, вы можете использовать Отражение , чтобы проверить, было ли введено значение.

// Sample with Queue instead of ConcurrentQueue
private void TestInsertInt(int id, int value)
{
    myInstance.InsertInt(id, value);

    FieldInfo field = myInstance.GetType().GetField("listOfQueues", BindingFlags.NonPublic | BindingFlags.Instance);
    List<Queue<int>> listOfQueues = field.GetValue(myInstance) as List<Queue<int>>;
    int lastInserted = listOfQueues[id].Last();

    Assert.AreEqual(lastInserted, value);
}
0 голосов
/ 03 июня 2011

Другой способ - использовать PrivateObject .

Лично я бы либо использовал DI (Dependency Injection), либо сделал бы private, internal для модульного тестирования!

0 голосов
/ 03 июня 2011

Это то, что я не должен быть единым целым тестирование?

Если вы нацелены на 100% тестовое покрытие, тогда да

Если это так, как я могу проверить InsertInt метод без использования каких-либо других методы?

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

  • Используйте другой метод доступа как Вы предлагаете.
  • Сделать контейнер внутренним и дать узлу модульного тестирования доступ к внутренним элементам
  • Разложите контейнер в отдельный класс, который вы передаете в качестве зависимости от этого класса, а затем в своем модульном тесте вместо него передаете фиктивный контейнер
  • Использовать отражение для доступа к приватным членам
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...