Внекодированная пересылка для проверки частных методов

В целом, я проектирую классы таким образом, чтобы не требовать доступа к частным лицам для целей тестирования. InternalsVisibleTo также может помочь.

Однако в настоящее время я имею дело с кодовой базой, которая имеет несколько областей, которые стали полагаться на механизм [private accessors в VSTS] (http://msdn.microsoft.com/en-us/library/ms184807(VS.80).aspx) (т.е. используя VSCodeGenAccessors для генерации *_Accessor классов, которые имеют переадресацию, которые используют отражение для вызова членов private (и необязательно internal тоже) для класса.

Итак, у меня есть код вроде:

ClassUnderTest target = new ClassUnderTest();
var accessor = ClassUnderTest_Accessor.AttachShadow( target );
accessor.PrivateMethod();
Assert.True( accessor._privateMethodWasCalled);
accessor.PrivateProperty = 5;
Assert.Equal( accessor.PrivateProperty, 5);

(Да, пронизан антипаттернами - но, пожалуйста, не стреляйте в посланника)

У меня есть ряд проблем с этим:

  • Я хотел бы иметь возможность уточнить, что мне нужно, я нуждаюсь.
  • Я бы предпочел не вызывать диалоги (да, я CRaholic)
  • Я бы предпочел не включать генерацию кода в изображение

Итак, я хотел бы иметь возможность преобразовать вышеуказанный код в нечто вроде:

var target = new ClassUnderTest();
IClassUnderTestInterface accessor = Shadow.Create<IClassUnderTestInterface>( target );
accessor.PrivateMethod();
Assert.True( accessor._privateMethodWasCalled);
accessor.PrivateProperty = 5;
Assert.Equal( accessor.PrivateProperty, 5);

Если в моей тестовой сборке сидит только следующий интерфейс и не генерируется код или пользовательские шаги сборки: -

interface IClassUnderTestInterface
{
   int PrivateProperty {get; set;}
   bool _privateMethodWasCalled {get; }
   void PrivateMethod();
}

Оттуда я смогу использовать CodeRush или Ctrl K M, чтобы создавать новые теневые методы на интерфейсе только с нажатием клавиши.

Пропущенный бит будет иметь метод I Shadow.Create<I>( Object o), который 1. создать динамический прокси-сервер, который реализует интерфейс 1. убедитесь, что объект o, который должен быть обернут, имеет все члены, продиктованные интерфейсом 1. bnous: правильно управлять пересылкой свойств, представляющих поля (например, случай `_privateMethodWasCalled ')

Итак, кто-нибудь знает библиотеку, которая реализует нечто подобное (или достаточно скучно, чтобы написать ее?)

Один очевидный недостаток заключается в том, что youo не знает, совместим ли интерфейс с ClassUnderTest до времени выполнения, но это нормально, поскольку это будет только для тестов. Также AIUI, механизм частных аксессуаров также требует время от времени перекомпилировать синхронизацию.

Или есть способ лучшего подхода, который мне не хватает? (Вспоминая, что я не хочу уходить, одевая al privates во внутренние или публичные и не хочу переписывать рабочий код)

Использование xUnit.net,.NET 3.5; Откройте для использования любую динамическую прокси-библиотеку или другую

Ответы

Ответ 1

Я закончил маршрутизацию всего этого материала (InternalsVisibleTo, отдельные тестовые проекты, тестовые ссылки, частные аксессоры, MSBuild Shadow task/publicize.exe, случайно выполняемые в сборках, используя отражение для доступа к частным лицам) путем слияния тестов в основные проекты и сделать все, что нужно было получить из тестов internal). См. Также xUnit.net Test Stripper [удалить тестовый код, встроенный в двоичные файлы до развертывания/доставки]

Ответ 2

Вы смотрели на насмешливые рамки, такие как Moq или Rhino? В вашем случае они могли бы помочь, если вы готовы изменить рядовых, что вам нужно протестировать "защищенный виртуальный" (что не так уж плохо публикует внутреннее). В принципе, если член является виртуальным, то mocking framework может генерировать подкласс, который записывает, какие члены вызываются.

Ответ 3

Этот опрятный трюк, который может сделать функции пересылки более сукчинтными, хотя его все еще ручной характер

Кроме того, этот ответ описывает, как обращаться с членами static (но требует CLR4, который не был в игре во время моего запроса и не обрабатывал частные методы без приведения InternalsVisibleTo в микс).