Ответ 1
В теории абсолютно нет проблем, издевающихся над конкретным классом; мы тестируем логический интерфейс (а не ключевое слово interface
), и неважно, обеспечивается ли этот логический интерфейс с помощью class
или interface
.
На практике .NET/С# делает это немного проблематичным. Как вы уже сказали,.NET mocking framework я собираюсь предположить, что вы ограничены этим.
В .NET/С# члены по умолчанию не виртуальны, поэтому любые прокси-методы издевательского поведения (т.е. вывод из класса и переопределение всех членов, чтобы делать тестовые данные) не будут работать, если вы явно не используете отметьте элементы как virtual
. Это приводит к проблеме: вы используете экземпляр издевающегося класса, который должен быть полностью безопасным в вашем unit test (т.е. Не будет запускать какой-либо реальный код), но если вы не убедитесь, что все есть virtual
, вы может закончиться сочетанием реального и запутанного кода (это может быть особенно проблематичным, если есть логика конструктора, которая всегда выполняется, и усугубляется, если есть другие конкретные зависимости, которые должны быть новыми).
Есть несколько способов обойти это.
- Используйте
interfaces
. Это работает, и это то, что мы советуем в документации NSubstitute, но имеет недостаток потенциально раздувания вашей базы кода с интерфейсами, которые на самом деле не нужны. Возможно, если мы найдем хорошие абстракции в нашем коде, мы, естественно, получим аккуратные интерфейсы, которые можно использовать повторно, с которыми мы можем протестировать. Я не совсем видел, как это происходит, но YMMV.:) - Успокойтесь, чтобы все было виртуально. Спорным недостатком этого является то, что мы предлагаем, чтобы все эти члены были точками расширения в нашем дизайне, когда мы действительно хотим изменить поведение всего класса для тестирования. Он также не останавливает выполнение логики конструктора и не помогает, если конкретный класс требует других зависимостей.
- Используйте перезапись сборки через нечто вроде надстройки Virtuosity для Fody, которая вы можете использовать для изменения всех членов класса в своей сборке, чтобы быть виртуальными.
- Использовать смехотворную библиотеку, отличную от прокси-сервера, например TypeMock (оплачивается), JustMock (оплачивается), Microsoft Fakes (требуется VS Ultimate/Enterprise, хотя его предшественник, Microsoft Moles, является бесплатным) или Prig (бесплатный + открытый исходный код). Я считаю, что они способны издеваться над всеми аспектами классов, а также с статическими членами.
Общая жалоба, поданная против последней идеи, заключается в том, что вы тестируете через "поддельный" шов; мы выходим за пределы механизмов, обычно используемых для расширения кода, чтобы изменить поведение нашего кода. Необходимость выйти за пределы этих механизмов может указывать на жесткость в нашем дизайне. Я понимаю этот аргумент, но я видел случаи, когда шум создания другого интерфейса перевешивает преимущества. Я думаю, это вопрос осознания потенциальной проблемы дизайна; если вам не нужна эта обратная связь от тестов, чтобы подчеркнуть жесткость конструкции, тогда они отличные решения.
Окончательная идея, которую я выкину, заключается в том, чтобы поиграть с изменением размера единиц в наших тестах. Обычно у нас есть один класс как единица. Если у нас есть ряд связных классов в качестве нашего устройства и интерфейсы, действующие как четко определенная граница вокруг этого компонента, то мы можем избежать необходимости издеваться над таким количеством классов и вместо этого просто высмеивать более устойчивую границу. Это может сделать наши тесты более сложными, с тем преимуществом, что мы тестируем единую функциональность и поощряем разработку твердых интерфейсов вокруг этого устройства.
Надеюсь, что это поможет.