【问题标题】:Correctly Unit Test Service / Repository Interaction正确单元测试服务/存储库交互
【发布时间】:2009-07-03 16:54:29
【问题描述】:

我有一个要进行单元测试的方法 CreateAccount(...)。基本上它创建一个帐户实体并将其保存到数据库中,然后返回新创建的帐户。我正在嘲笑存储库并期待一个 Insert(...) 调用。但是 Insert 方法需要一个 Account 对象。

这个测试通过了,但它似乎不正确,因为 CreateAccount 创建了一个帐户,而我正在为模拟的预期调用创建一个帐户(两个单独的 Account 实例)。测试这种方法的正确方法是什么?还是我使用这种方法创建帐户不正确?

[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);
    }

这里是 CreateAccount 方法:

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;
    }

【问题讨论】:

    标签: unit-testing tdd rhino-mocks


    【解决方案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);
    }
    

    所以你在这里测试的本质上是一个工厂方法(即它创建一个对象的新实例并返回它)。我知道测试这些方法的唯一方法是检查我们是否返回了一个具有我们期望的属性的对象(上面的最后两个 Assert.Equal 调用正在执行此操作)。您在方法中对存储库进行了额外调用;所以我们需要额外的 AssertWasCalled 调用和上面的属性比较(以确保对象的正确实例被用作此调用的参数)。

    【讨论】:

    • 对不起,我应该发布我正在测试的实际方法,呵呵。我更新了 OP。
    • 我看不出 newAcc 和 account 是如何相同的,因为创建了 2 个单独的实例。还是 AreSame() 只是比较类型?
    • 正确。 AreSame 比较对象的实例,所以我上面的原始答案是不正确的。我已经添加了一些更正(在顶部)
    • 好的,这很有道理。所以总的来说,这是一个有效的单元测试吗?还是有更好的方法我应该这样做?我的单元测试应该这么细吗?或者这可能不够精细?
    • 我认为这是一个有效的测试,因为它描述了被测方法的行为。然而,您的测试方法似乎违反了单一职责原则,因为它创建了一个新的 Account 实例并将其插入到存储库中。其有效性取决于您的设计:如果不插入存储库就不应创建帐户,我想这一切都很好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-13
    • 1970-01-01
    相关资源
    最近更新 更多