Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this a poor design?

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.

like image 276
Kenneth Cochran Avatar asked Jun 10 '09 15:06

Kenneth Cochran


People also ask

What is poor design?

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.

What is good design and poor design?

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.


1 Answers

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...

  • You may want to consider using a Mocking framework such as Rhino Mocks (or Moq) which allow you to avoid using strings for your assertions.

  _mockAccountService.Expect(mock => mock.Create())
     .Return(_account);

  • If you are doing BDD style one common pattern I've seen is using chained classes for test setup. In your example...
public class MainPresenterSpec 
{
    // Protected variables for Mocks 

    [SetUp]
    public void Setup()
    {
       // Setup Mocks
    }

}

[TestFixture]
public class WhenUserAddsAccount : MainPresenterSpec
{
    [Test]
    public void ShouldCreateNewAccount()
    {
    }
}
  • Also I'd recommend changing your code to use a guard clause..
     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);
     }
like image 181
Shane Courtrille Avatar answered Sep 23 '22 06:09

Shane Courtrille