I'm trying my hand at behavior driven development and I'm finding myself second guessing my design as I'm writing it. This is my first greenfield project and it may just be my lack of experience. Anyway, here's a simple spec for the class(s) I'm writing. It's written in NUnit in a BDD style instead of using a dedicated behavior driven framework. This is because the project targets .NET 2.0 and all of the BDD frameworks seem to have embraced .NET 3.5.
[TestFixture]
public class WhenUserAddsAccount
{
private DynamicMock _mockMainView;
private IMainView _mainView;
private DynamicMock _mockAccountService;
private IAccountService _accountService;
private DynamicMock _mockAccount;
private IAccount _account;
[SetUp]
public void Setup()
{
_mockMainView = new DynamicMock(typeof(IMainView));
_mainView = (IMainView) _mockMainView.MockInstance;
_mockAccountService = new DynamicMock(typeof(IAccountService));
_accountService = (IAccountService) _mockAccountService.MockInstance;
_mockAccount = new DynamicMock(typeof(IAccount));
_account = (IAccount)_mockAccount.MockInstance;
}
[Test]
public void ShouldCreateNewAccount()
{
_mockAccountService.ExpectAndReturn("Create", _account);
MainPresenter mainPresenter = new MainPresenter(_mainView, _accountService);
mainPresenter.AddAccount();
_mockAccountService.Verify();
}
}
None of the interfaces used by MainPresenter have any real implementations yet. AccountService will be responsible for creating new accounts. There can be multiple implementations of IAccount defined as separate plugins. At runtime, if there is more than one then the user will be prompted to choose which account type to create. Otherwise AccountService will simply create an account.
One of the things that has me uneasy is how many mocks are required just to write a single spec/test. Is this just a side effect of using BDD or am I going about this thing the wrong way?
[Update]
Here's the current implementation of MainPresenter.AddAccount
public void AddAccount()
{
IAccount account;
if (AccountService.AccountTypes.Count == 1)
{
account = AccountService.Create();
}
_view.Accounts.Add(account);
}
Any tips, suggestions or alternatives welcome.
Bad Design is Boring Every single thing about the product was so easy to understand that we didn't have to think. While a good design emphasizes on making the interaction between the product and the user as seamless as possible, a good design also makes the users think.
Good design emphasizes the usefulness of a product whilst disregarding anything that could possibly detract from it. Bad design is one which is not easy to understand, distracting, difficult to use and short lived.
When doing top to down development it's quite common to find yourself using a lot of mocks. The pieces you need aren't there so naturally you need to mock them. With that said this does feel like an acceptance level test. In my experience BDD or Context/Specification starts to get a bit weird at the unit test level. At the unit test level I'd probably be doing something more along the lines of...
when_adding_an_account should_use_account_service_to_create_new_account should_update_screen_with_new_account_details
You may want to reconsider your usage of an interface for IAccount. I personally stick with keeping interfaces for services over domain entities. But that's more of a personal preference.
A few other small suggestions...
_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); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With