Correctly Unit Test Service / Repository Interacti

2019-09-06 01:32发布

问题:

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 = "test@asdf.com";
        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:

[Test]
public void can_create_account()
{
    const string email = "test@asdf.com";
    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).