Может быть, IsNullOrWhiteSpace
это метод, который вы ищете? http://msdn.microsoft.com/en-us/library/system.string.isnullorwhitespace.aspx
При разработке сверху вниз довольно часто обнаруживается, что вы используете множество имитаторов. Нужных вам частей нет, поэтому, естественно, вам нужно издеваться над ними. С учетом сказанного, это действительно похоже на тест на приемочный уровень. По моему опыту, BDD или Контекст / Спецификация начинает становиться немного странным на уровне модульного тестирования. На уровне модульного тестирования я бы, вероятно, сделал что-то большее, вроде ...
when_adding_an_account should_use_account_service_to_create_new_account should_update_screen_with_new_account_details
Возможно, вы захотите пересмотреть свое использование интерфейса для IAccount. Я лично придерживаюсь с сохранением интерфейсов для сервисов над объектами домена. Но это больше личное предпочтение.
Несколько других небольших предложений ...
_mockAccountService.Expect(mock => mock.Create()) .Return(_account);
public class MainPresenterSpec { // Protected variables for Mocks [SetUp] public void Setup() { // Setup Mocks } } [TestFixture] public class WhenUserAddsAccount : MainPresenterSpec { [Test] public void ShouldCreateNewAccount() { } }
public void AddAccount() { if (AccountService.AccountTypes.Count != 1) { // Do whatever you want here. throw a message? return; } IAccount account = AccountService.Create(); _view.Accounts.Add(account); }
Тестирование жизнеобеспечения будет намного проще, если вы используете контейнер автоматического имитации, такой как RhinoAutoMocker (часть StructureMap ). Вы используете контейнер auto mocking для создания тестируемого класса и запрашиваете у него зависимости, необходимые для теста (ов). Контейнеру может потребоваться ввести 20 элементов в конструктор, но если вам нужно протестировать только одно, вам нужно только запросить его.
using StructureMap.AutoMocking;
namespace Foo.Business.UnitTests
{
public class MainPresenterTests
{
public class When_asked_to_add_an_account
{
private IAccountService _accountService;
private IAccount _account;
private MainPresenter _mainPresenter;
[SetUp]
public void BeforeEachTest()
{
var mocker = new RhinoAutoMocker<MainPresenter>();
_mainPresenter = mocker.ClassUnderTest;
_accountService = mocker.Get<IAccountService>();
_account = MockRepository.GenerateStub<IAccount>();
}
[TearDown]
public void AfterEachTest()
{
_accountService.VerifyAllExpectations();
}
[Test]
public void Should_use_the_AccountService_to_create_an_account()
{
_accountService.Expect(x => x.Create()).Return(_account);
_mainPresenter.AddAccount();
}
}
}
}
Структурно я предпочитаю использовать подчеркивания между словами вместо RunningThemAllTogether, так как мне легче сканировать. Я также создаю внешний класс с именем тестируемого класса и несколько внутренних классов с именем тестируемого метода. Затем методы тестирования позволяют указать поведение тестируемого метода. При запуске в NUnit это дает вам контекст вроде:
Foo.Business.UnitTests.MainPresenterTest
When_asked_to_add_an_account
Should_use_the_AccountService_to_create_an_account
Should_add_the_Account_to_the_View
Это похоже на правильное количество имитаторов для докладчика со службой, которая должна вернуть учетную запись.
Это больше похоже на приемочный тест, чем на модульный тест, хотя - возможно, если вы уменьшите сложность утверждения, вы обнаружите, что высмеивается меньший набор проблем.
Да, ваш дизайн ошибочен. Вы используете mocks :)
Если серьезно, я согласен с предыдущим постером, который предлагает, чтобы ваш дизайн был многоуровневым, чтобы каждый слой можно было тестировать отдельно. Я считаю, что в принципе неверно, что тестируемый код должен изменять фактический производственный код - если это не может быть сделано автоматически и прозрачно, как код может быть скомпилирован для отладки или выпуска.
Это похоже на принцип неопределенности Гейзенберга - если у вас есть там есть макеты, ваш код настолько изменен, что становится головной болью при обслуживании, а сами макеты потенциально могут вносить или маскировать ошибки.
Если у вас чистые интерфейсы, я не спорю с реализацией простого интерфейса, который имитирует (или mocks) нереализованный интерфейс с другим модулем. Эту симуляцию можно использовать так же, как насмешку,
Я считаю, что если вам нужны моки, ваш дизайн неверен.
Компоненты должны быть многоуровневыми. Вы создаете и тестируете компоненты A изолированно. Затем вы создаете и тестируете B + A. В случае успеха вы создаете слой C и тестируете C + B + A.
В вашем случае вам не понадобится "_mockAccountService". Если ваш реальный AccountService был протестирован, просто используйте его. Таким образом, вы будете знать, что любые ошибки есть в MainPresentor, а не в самом макете.
Если ваш реальный AccountService не был протестирован, остановитесь. Вернитесь и сделайте то, что вам нужно, чтобы убедиться, что он работает правильно. Доведите его до такой степени, чтобы на него действительно можно было положиться, и тогда макет вам не понадобится.
Возможно, вы захотите использовать MockContainers , чтобы избавиться от всего фиктивного управления при создании презентатора. Это значительно упрощает модульные тесты.
Это нормально, но я бы ожидал, что где-то там будет контейнер для автозапуска IoC. Код намекает на то, что автор теста вручную (явно) переключается между имитируемыми и реальными объектами в тестах, чего не должно быть, потому что, если мы говорим о тесте unit (где unit представляет собой только один класс), это проще просто автоматически смоделировать все остальные классы и использовать макеты.
Я пытаюсь сказать, что если у вас есть тестовый класс, который использует как mainView
, так и mockMainView
, у вас нет модульного теста в строгом смысле этого слова - больше похоже на интеграционный тест.