Хороший вопрос.
Прежде всего, чувство соблазна использовать AbstractFactories везде пахнет немного, поскольку DI-контейнер не используется «правильным» способом, или дизайн может быть улучшен.
Но иногда я тоже сталкивался с этой проблемой. Я вижу следующее:
- используя AbstractFactory / Factory и внедрите его. Для C # вы должны иметь преимущество в том, что вы можете передавать делегатов, выступая в качестве интерфейса для создания экземпляра.
- 'new' в порядке, просто проверьте вывод 'new'.
- Заглушить вызов 'new' внутри извлеченного метода (хакерский !!)
Инъекция уже упоминалась, поэтому я не буду повторяться. Я больше разбираюсь в Java, поэтому прошу прощения за некоторые синтаксические ошибки.
Проверьте вывод 'new'
Я часто использую это, если «новые» созданные экземпляры являются объектами предметной области, а не службами. Поскольку он возвращается непосредственно в методе, я могу проверить прямой вывод с помощью своего теста.
Prod-Code:
...
public override IRenderable GetRenderable()
{
var val = SomeCalculationUsingClassMemberVariables();
return new EquationRenderable(val);
}
Test Case:
...
[Test]
public void test_new()
{
SUT sut = ...;
IRenderable r = sut.GetRenderable();
assertTrue(r instanceof EquationRenderable);
}
Заглушите зов самого "нового"
Тестирование прямого вывода сверху возможно только в том случае, если вы каким-то образом получаете его в качестве возвращаемого значения. Ситуация усложняется, если «побочным эффектом» вашего кода являются косвенные выходные данные, которые вы не можете непосредственно определить по возвращаемому значению. Если так, то я часто извлекаю метод нового создания, а затем проверяю его. Это отвратительно, и я больше использую его, чтобы безопасно пройти тест и позже начать проводить рефакторинг (DI и фабрики). Иногда я делаю это в унаследованном коде, где сервисы создаются с «новым» напрямую, а рефакторинг для DI слишком рискован без тестов.
Prod-Code:
...
public override IRenderable GetRenderable()
{
var val = SomeCalculationUsingClassMemberVariables();
return createEquationRenderable();
}
public IRenderable createEquationRenderable()
{
return new EquationRenderable(val);
}
Test Case:
...
class Stubbed : SUT
{
boolean called = false;
public override EquationRenderable createEquationRenderable()
{
called=true;
return MyMock();
}
}
[Test]
public void test_new()
{
Stubbed sut = new Stubbed();
sut.GetRenderable();
assertTrue(sut.called);
// do further stuff on MyMock
}
Я знаю, пример излишний и немного бессмысленный, он просто для описания идеи. Я уверен, что выше может быть сокращен с mocking-frameworks для C #. В любом случае тестирование прямого вывода возвращаемого значения более тривиально и лучше подходит здесь.
Может быть, у вас есть более подробный пример?