Я обнаружил, что существует только 3 способа статических зависимостей модульного тестирования (макет / заглушка) в C # .NET:
Учитывая, что два из них не бесплатны, а один не выпущен в версии 1.0, издеваться над статичными вещами не так уж и легко.
Имеет ли это статические методы и такое «зло» (в смысле модульного тестирования)? И если да, то почему Resharper хочет, чтобы я сделал все, что может быть статичным, статичным? (Предполагая, что резарпер тоже не «зло».)
Пояснение: я говорю о сценарии, когда вы хотите выполнить модульное тестирование метода, и этот метод вызывает статический метод в другом модуле / классе. В большинстве определений модульного тестирования, если вы просто позволяете тестируемому методу вызывать статический метод в другом модуле / классе, то вы не модульное тестирование, а интеграционное тестирование. (Полезно, но не юнит-тест.)
источник
Ответы:
Глядя на другие ответы здесь, я думаю, что может быть некоторая путаница между статическими методами, которые поддерживают статическое состояние или вызывают побочные эффекты (что звучит для меня очень плохой идеей), и статическими методами, которые просто возвращают значение.
Статические методы, которые не содержат состояния и не вызывают побочных эффектов, должны легко тестироваться модулем. Фактически, я считаю такие методы формой функционального программирования для «бедняков»; вы передаете методу объект или значение, и он возвращает объект или значение. Ничего больше. Я не понимаю, как такие методы могут негативно повлиять на юнит-тестирование.
источник
Вы, кажется, путаете статические данные и статические методы . Решарпер, если я правильно помню, рекомендует делать
private
методы внутри класса статичными, если они могут быть сделаны так - я считаю, что это дает небольшое преимущество в производительности. Он не рекомендует делать «все, что может быть» статичным!В статических методах нет ничего плохого, и их легко тестировать (если они не изменяют статические данные). Например, подумайте о библиотеке Maths, которая является хорошим кандидатом для статического класса со статическими методами. Если у вас есть (надуманный) метод, подобный этому:
тогда это в высшей степени проверяемое и не имеет побочных эффектов. Вы просто проверяете, что когда вы проходите, скажем, 20, вы получаете 400. Нет проблем.
источник
System.Math
), не говоря уже об обилии статических фабричных методов и т. Д. Кроме того, вы никогда не сможете использовать какие-либо методы расширения и т. Д. Дело в том, что простые функции, подобные этой, фундаментальное значение для современных языков. Вы можете проверить их изолированно (так как они обычно будут детерминированными), а затем использовать их в своих классах без беспокойства. Это не проблема!Если реальный вопрос здесь - «Как мне проверить этот код?»:
Затем просто реорганизуйте код и вставьте как обычно вызов статического класса следующим образом:
источник
Статика не обязательно является злой, но она может ограничить ваши возможности, когда дело доходит до юнит-тестирования с помощью fakes / mocks / stubs.
Есть два основных подхода к насмешкам.
Первый (традиционный - реализованный RhinoMocks, Moq, NMock2; ручные макеты и заглушки также находятся в этом лагере) основан на тестовых швах и внедрении зависимостей. Предположим, вы тестируете модульный код и у него есть зависимости. В коде, разработанном таким образом, часто происходит то, что статика создает свои собственные зависимости, инвертируя инверсию зависимостей . Вскоре вы обнаружите, что не можете внедрить макетированные интерфейсы в тестируемый код, разработанный таким образом.
Второй (макет чего-либо - реализованный TypeMock, JustMock и Moles) использует API профилирования .NET . Он может перехватить любую из ваших инструкций CIL и заменить часть вашего кода на фальшивую. Это позволяет TypeMock и другим продуктам в этом лагере макетировать что угодно: статику, закрытые классы, частные методы - вещи, не предназначенные для тестирования.
Между двумя школами мысли продолжаются дебаты. Кто-то говорит: следуйте принципам SOLID и проектируйте для обеспечения тестируемости (это часто включает в себя упрощение статики). Другой говорит, купи TypeMock и не волнуйся.
источник
Проверьте это: «Статические методы - смерть для тестируемости» . Краткое резюме аргумента:
Для модульного тестирования вам нужно взять небольшой кусочек кода, перепрограммировать его зависимости и протестировать его изолированно. Это сложно сделать со статическими методами, не только в том случае, если они обращаются к глобальному состоянию, но даже если они просто вызывают другие статические методы.
источник
Простая истина, редко признаваемая в том, что если класс содержит видимую компилятором зависимость от другого класса, он не может быть протестирован изолированно от этого класса. Вы можете подделать что-то, похожее на тест, и появится в отчете, как если бы это был тест.
Но у него не будет ключа, определяющего свойства теста; терпеть неудачу, когда что-то не так, проходить, когда они правы.
Это относится ко всем статическим вызовам, вызовам конструктора и любой ссылке на методы или поля, не унаследованные от базового класса или интерфейса . Если имя класса появляется в коде, это зависимость, видимая компилятору, и вы не можете проверить ее без него. Любой меньший кусок просто не является допустимым тестируемым модулем . Любая попытка трактовать его так, как если бы он был, будет иметь результаты, не более значимые, чем написание небольшой утилиты для выдачи XML, используемого вашей тестовой средой, чтобы сказать «тест пройден».
Учитывая это, есть три варианта:
определить модульное тестирование как тестирование модуля, состоящего из класса и его жестко закодированных зависимостей. Это работает, если вы избегаете циклических зависимостей.
никогда не создавайте зависимости времени компиляции между классами, за которые вы отвечаете за тестирование. Это работает, если вы не возражаете против стиля кода.
не юнит-тест, а интеграционный тест. Что работает, при условии, что это не конфликтует с чем-то еще, для чего вам нужно использовать термин интеграционное тестирование.
источник
Math.Pi
в методе не делает его интеграционным тестом по какому-либо разумному определению.Там нет двух способов об этом. Предложения ReSharper и некоторые полезные функции C # не будут использоваться так часто, если вы пишете отдельные атомарные модульные тесты для всего своего кода.
Например, если у вас есть статический метод, и вам нужно его заглушить, вы не сможете, если не используете каркас изоляции на основе профиля. Совместимый с вызовом обходной путь - изменить верхнюю часть метода, чтобы использовать лямбда-нотацию. Например:
ДО:
ПОСЛЕ:
Два совместимы по вызову. Абоненты не должны меняться. Тело функции остается прежним.
Затем в своем коде Unit-Test вы можете заглушить этот вызов следующим образом (при условии, что он находится в классе с именем Database):
Будьте осторожны, чтобы заменить его исходным значением после того, как вы закончите. Вы можете сделать это с помощью try / finally или, в вашем модульном тесте, который вызывается после каждого теста, написать такой код:
который повторно вызовет статический инициализатор вашего класса.
Лямбда-функции не так богаты в поддержке, как обычные статические методы, поэтому этот подход имеет следующие нежелательные побочные эффекты:
Но допустим, вы вообще избегаете статики и конвертируете это в метод экземпляра. Он по-прежнему не может быть надуманным, если метод не является виртуальным или реализован как часть интерфейса.
Таким образом, на самом деле, любой, кто предлагает исправить заглушку статическими методами, должен сделать их экземплярами методов, они также будут против методов экземпляров, которые не являются виртуальными или являются частью интерфейса.
Так почему же в C # есть статические методы? Почему он допускает не виртуальные методы экземпляра?
Если вы используете одну из этих «функций», то вы просто не сможете создавать изолированные методы.
Так когда вы их используете?
Используйте их для любого кода, который, как вы ожидаете, никто не захочет заглушить. Некоторые примеры: метод Format () класса String, метод WriteLine () класса Console, метод Cosh () класса Math.
И еще одна вещь. Большинству людей это не нужно, но если вы можете узнать о производительности косвенного вызова, это еще одна причина избегать методов экземпляра. Есть случаи, когда это удар по производительности. Вот почему существуют не виртуальные методы.
источник
R # не единственный инструмент, который сделает это предложение. FxCop / MS Code Analysis также сделает то же самое.
Я бы вообще сказал, что если метод статический, то в целом он должен быть тестируемым, как есть. Это вызывает некоторое внимание к дизайну и, возможно, больше обсуждения, чем у меня сейчас, так терпеливо ожидая отрицательных голосов и комментариев ...;)
источник
Я вижу, что после долгого времени никто еще не установил действительно простой факт. Если resharper говорит мне, что я могу сделать метод статичным, это значит для меня огромную вещь, я слышу, как его голос говорит мне: «Эй, вы, эти кусочки логики не являются ОТВЕТСТВЕННОСТЬЮ текущего класса, чтобы справиться, поэтому он должен остаться вне в каком-то вспомогательном классе или что-то ".
источник
Если статический метод вызывается из другого метода , невозможно предотвратить или заменить такой вызов. Это означает, что эти два метода составляют единое целое; Юнит тест любого вида тестирует их обоих.
И если этот статический метод общается с Интернетом, соединяет базы данных, показывает всплывающие окна с графическим интерфейсом или иным образом преобразует модульный тест в полный беспорядок, он просто обходится без какой-либо легкой работы. Метод, который вызывает такой статический метод, не может быть протестирован без рефакторинга, даже если он имеет много чисто вычислительного кода, который будет очень полезен при модульном тестировании.
источник
Я считаю, что Resharper дает вам рекомендации и применяет принципы кодирования, с которыми он был настроен. Когда я использовал Resharper и он сказал мне, что метод должен быть статическим, он обязательно должен быть закрытым методом, который не действует ни на какие переменные экземпляра.
Теперь, что касается тестируемости, этот сценарий не должен быть проблемой, так как вы все равно не должны тестировать приватные методы.
Что касается тестируемости открытых статических методов, то модульное тестирование становится трудным, когда статические методы касаются статического состояния. Лично я бы свел это к минимуму и использовал бы статические методы как можно более чистые функции, если в метод передаются любые зависимости, которыми можно управлять с помощью тестового прибора. Однако это дизайнерское решение.
источник