views:

108

answers:

1

I have a method CreateAccount(...) that I want to unit test. Basically it creates an Account Entity and saves it to the DB, then returns the newly created Account. I am mocking the Repository and expecting an Insert(...) call. But the Insert method expects an Account object.

This test passes, but it just does not seem correct, because CreateAccount creates an account, and I am creating an account for the Mock'ed expected call (two seperate Account instances). What would be the correct way to test this method? Or is me creating Accounts using this method incorrect?

[Fact]
    public void can_create_account()
    {
        const string email = "[email protected]";
        const string password = "password";
        var accounts = MockRepository.GenerateMock<IAccountRepository>();
        accounts.Expect(x => x.Insert(new Account()));
        var service = new AccountService(accounts);

        var account = service.CreateAccount(email, password, string.Empty, string.Empty, string.Empty);

        accounts.VerifyAllExpectations();
        Assert.Equal(account.EmailAddress, email);
    }

And here is the CreateAccount Method:

public Account CreateAccount(string email, string password, string firstname, string lastname, string phone)
    {
        var account = new Account
                          {
                              EmailAddress = email,
                              Password = password,
                              FirstName = firstname,
                              LastName = lastname,
                              Phone = phone
                          };

        accounts.Insert(account);
        return account;
    }
+1  A: 
[Test]
public void can_create_account()
{
    const string email = "[email protected]";
    const string password = "password";

    Account newAcc = new Account();
    var accounts = MockRepository.GenerateMock<IAccountRepository>();

    var service = new AccountService(accounts);
    var account = service.CreateAccount(email, password, string.Empty, 
                                        string.Empty, string.Empty);

    accounts.AssertWasCalled(x => x.Insert(Arg<Account>
                            .Matches(y => y.EmailAddess == email 
                                       && y.Password == password)));                   

    Assert.AreEqual(email, account.EmailAddress);
    Assert.AreEqual(password, account.Password);
}

So what you're testing here is essentially a factory method (i.e. it creates a new instance of an object and returns it). The only way that I know of testing these sorts of methods is by checking that we get returned an object with the properties that we are expecting (the last two Assert.Equal calls above are doing this). You have an additional call to a repository in your method; and so we need the additional AssertWasCalled call with the property comparison as above (to make sure that the right instance of object was used as a parameter to this call).

jpoh
Sorry, I should have posted the actual method I was testing, duh. I updated the OP.
mxmissile
I dont see how newAcc and account would be the same since 2 separate instances are created. Or does AreSame() just compare type?
mxmissile
Correct. AreSame compares instances of objects so my original answer above is incorrect. I have since added some corrections (on top)
jpoh
Ok, that makes sense. So in general, is this a valid unit test? Or is there a better way I should be doing this? Should my unit tests be this fine grained? Or perhaps this is not fine grained enough?
mxmissile
I think it's a valid test in that it describes the behaviour of your method under test. Your method under test however appears to violate the Single Responsibility Principle in that it creates a new instance of an Account and inserts it into the repository. The validity of that depends on your design: if Accounts should not be created without being inserted into the repository, I guess then all of this is alright.
jpoh