С# "внутренний" модификатор доступа при выполнении модульного тестирования

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

Ответ 1

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

using System.Runtime.CompilerServices;

[assembly:InternalsVisibleTo("MyTests")]

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

Ответ 2

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

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

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

Ответ 3

Добавив к ответу Эрика, вы также можете настроить это в файле 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>

см.: fooobar.com/questions/723527/...
Пример: https://github.com/gldraphael/evlog/blob/master/Directory.Build.props#L5-L12

Ответ 4

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

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

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

Ответ 5

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

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

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

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

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

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