C # «внутренний» модификатор доступа при выполнении юнит-тестирования

Я новичок в модульном тестировании и пытаюсь выяснить, стоит ли мне начинать использовать больше «внутреннего» модификатора доступа. Я знаю, что если мы используем 'internal' и устанавливаем переменную сборки 'InternalsVisibleTo', мы можем тестировать функции, которые не хотим объявлять public из проекта тестирования. Это заставляет меня думать, что я должен всегда использовать «внутренний», потому что, по крайней мере, у каждого проекта (должен?) Есть свой собственный проект тестирования. Ребята, можете ли вы сказать мне причину, почему я не должен этого делать? Когда я должен использовать «личное»?

11.12.2008 01:20:30
Стоит упомянуть - вы часто можете избежать необходимости модульного тестирования ваших внутренних методов, используя System.Diagnostics.Debug.Assert()сами методы.
Mike Marynowski 30.03.2017 02:32:34
6 ОТВЕТОВ
РЕШЕНИЕ

Внутренние классы должны быть проверены и есть атрибут сборки:

using System.Runtime.CompilerServices;

[assembly:InternalsVisibleTo("MyTests")]

Добавьте это в файл информации о проекте, например Properties\AssemblyInfo.cs.

1175
17.12.2014 23:51:28
Добавьте его в тестируемый проект (например, в Properties \ AssemblyInfo.cs). «MyTests» будет тестовой сборкой.
EricSchaefer 9.07.2010 05:32:20
Это действительно должен быть принятый ответ. Я не знаю, как вы, ребята, но когда тесты "слишком далеки" от кода, который они тестируют, я склонен нервничать. Я полностью за то, что стараюсь избегать тестирования чего-либо, помеченного как private, но слишком много privateвещей могут очень хорошо указать на internalкласс, который изо всех сил пытается быть извлеченным. TDD или нет TDD, я предпочитаю иметь больше тестов, которые тестируют большое количество кода, чем несколько тестов, которые выполняют одинаковое количество кода. А уклонение от тестирования internalне совсем помогает достичь хорошего соотношения.
s.m. 28.05.2012 07:50:53
Между @DerickBailey и Dan Tao идет большая дискуссия о семантической разнице между внутренним и частным и о необходимости тестирования внутренних компонентов. Стоит прочитать.
Kris McGinnes 21.01.2014 05:22:53
Обтекание в и #if DEBUG, #endifблок включит эту опцию только в отладочных сборках.
The Real Edward Cullen 4.02.2014 16:33:30
Это правильный ответ. Любой ответ, в котором говорится, что только общедоступные методы должны подвергаться модульному тестированию, упускает смысл модульных тестов и дает оправдание. Функциональное тестирование ориентировано на черный ящик. Модульные тесты ориентированы на белый ящик. Они должны тестировать «модули» функциональности, а не только публичные API.
Gunnar 18.08.2015 23:00:24

Вы также можете использовать private и вызывать private методы с отражением. Если вы используете Visual Studio Team Suite, у него есть хорошая функциональность, которая генерирует прокси для вызова ваших личных методов. Вот статья о проекте кода, которая демонстрирует, как вы можете выполнить работу самостоятельно для тестирования отдельных и защищенных методов:

http://www.codeproject.com/KB/cs/testnonpublicmembers.aspx

С точки зрения того, какой модификатор доступа вы должны использовать, мое общее эмпирическое правило - начинать с private и расширять по мере необходимости. Таким образом, вы будете раскрывать как можно меньше внутренних деталей вашего класса, и это поможет скрыть детали реализации, как и должно быть.

11
11.12.2008 01:53:23

Если вы хотите проверить личные методы, посмотреть на PrivateObjectи PrivateTypeв Microsoft.VisualStudio.TestTools.UnitTestingпространстве имен. Они предлагают простые в использовании обертки вокруг необходимого кода отражения.

Документы: PrivateType , PrivateObject

Для VS2017 и 2019 вы можете найти их, загрузив nuget MSTest.TestFramework

126
16.07.2019 03:44:21
При отрицательном голосовании, пожалуйста, оставьте комментарий. Спасибо.
Brian Rasmussen 30.07.2012 16:44:02
Глупо голосовать за этот ответ. Это указывает на новое решение и действительно хорошее, не упомянутое ранее.
Ignacio Soler Garcia 6.09.2012 07:43:13
По-видимому, существует некоторая проблема с использованием TestFramework для приложений, нацеленных на .net2.0 или более новую версию: github.com/Microsoft/testfx/issues/366
Johnny Wu 16.07.2019 00:42:21

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

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

Одна вещь, которую следует рассмотреть, может быть суффиксом «ForTest»:

internal void DoThisForTest(string name)
{
    DoThis(name);
}

private void DoThis(string name)
{
    // Real implementation
}

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

12
11.12.2008 06:27:57
Если метод является внутренним, не исключает ли это его использование из тестовой сборки?
Ralph Shillington 22.02.2010 15:47:42
Я иногда использую этот ForTestподход, но всегда нахожу его безобразным (добавление кода, который не дает никакой реальной ценности с точки зрения производственной бизнес-логики). Обычно я нахожу, что должен был использовать этот подход, потому что дизайн немного неудачный (то есть необходимость сбрасывать единичные экземпляры между тестами)
ChrisWue 3.04.2012 18:53:32
Соблазн понизить это - в чем разница между этим хаком и простым превращением класса в внутренний, а не в частный? Ну хотя бы с компиляцией условных. Тогда это становится действительно грязным.
CAD bloke 6.11.2013 10:18:09
@CADbloke: Вы хотите сделать метод внутренним, а не частным? Разница в том, что очевидно, что вы действительно хотите, чтобы это было приватно. Любой код в вашей производственной кодовой базе, который вызывает метод с ForTest, явно ошибочен, в то время как если вы просто сделаете метод внутренним, это будет выглядеть нормально.
Jon Skeet 6.11.2013 10:28:16
@CADbloke: Вы можете исключить отдельные методы в сборке релиза так же легко, как и частичные классы, IMO. И если вы это сделаете, это говорит о том, что вы не запускаете свои тесты для своей сборки выпуска, что для меня звучит как плохая идея.
Jon Skeet 6.11.2013 10:54:12

Добавив ответ Эрика, вы также можете настроить это в csprojфайле:

<ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
      <_Parameter1>MyTests</_Parameter1>
    </AssemblyAttribute>
</ItemGroup>

Или, если у вас есть один тестовый проект на тестируемый проект, вы можете сделать что-то вроде этого в вашем Directory.Build.propsфайле:

<ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
      <_Parameter1>$(MSBuildProjectName).Test</_Parameter1>
    </AssemblyAttribute>
</ItemGroup>

См .: https://stackoverflow.com/a/49978185/1678053
Пример: https://github.com/gldraphael/evlog/blob/master/Directory.Build.props#L5-L12.

31
18.09.2019 07:27:32

Я использую Dotnet 3.1.101и .csprojдополнения, которые работали для меня были:

<PropertyGroup>
  <!-- Explicitly generate Assembly Info -->
  <GenerateAssemblyInfo>true</GenerateAssemblyInfo>
</PropertyGroup>

<ItemGroup>
  <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
  <_Parameter1>MyProject.Tests</_Parameter1>
  </AssemblyAttribute>
</ItemGroup>

Надеюсь, это поможет кому-то там!

1
7.02.2020 06:29:41
Добавление явно генерируемой информации о сборке было тем, что, наконец, заставило ее работать и у меня. Спасибо за публикацию!
thevioletsaber 11.03.2020 16:16:57