添加到使用 TDD 进行单元测试的私有列表

Adding to private list for unit tests with TDD

我正在学习 TDD 和模拟,我想知道如何将一些对象添加到私有列表以测试方法和 属性。我的代码的基本部分如下:

public class Account
{
    private List<Transaction> transactions = new List<Transaction>();

    public decimal Balance
    {
        get
        {
            throw new NotImplementedException();
            // Should be calculated by adding amounts of all transactions 
            // from private list
        }
    }

    public void AddTransaction(Transaction transaction)
    {
        throw new NotImplementedException();
    }
}

public class Transaction
{
    public decimal Amount { get; set; }
    public string Note { get; set; }
    public DateTime DateTime { get; set; }

    public Transaction(decimal amount, string note, DateTime dateTime)
    {
        Amount = amount;
        Note = note;
        DateTime = dateTime;
    }
}

我想测试 属性 余额,但我不知道如何向列表中添加一些数据。我可以使用 Mock 来做到这一点,还是应该先为 AddTransaction 编写代码,然后在余额测试中使用它?

我可以想到三种可能的选项来测试这种代码。

  1. 如您所述,实施 AddTransaction 代码并在您的测试中使用它来比较 Balance 的值。
  2. 您可以潜在地进行交易 属性 public 并在您的测试中模拟它。
  3. 修改账户 class 通过添加一个构造函数,允许您使用交易参数初始化账户,然后您可以模拟交易并将其注入测试中的 class。

您应该仅使用暴露给消费者的 public "endpoints" 来测试您的 class。
在您的情况下,它将是 constructorAddTransactionBalance。 您的 class 的职责是添加交易并计算余额。
因此,在您的测试中,您将添加交易并检查 Balance returns 预期结果。 AddTransaction 方法将通过 Balance 属性.

的测试进行测试

如果您首先通过编写测试来接近解决方案,那么您无需关心是否有私有列表或字典或其他东西。

例如第一个测试看起来像

var transaction = new Transaction(12.4m, "note", 12.January(2018));
var account = new Account();

account.AddTransaction(transaction);

account.Balance.Should().Be(12.4m);

第二次测试

var transaction1 = new Transaction(50.00m, "note1", 12.January(2018));
var transaction2 = new Transaction(45.99m, "note2", 13.January(2018));
var transaction3 = new Transaction(4.01m, "note3", 14.January(2018));
var account = new Account();

account.AddTransaction(transaction1);
account.AddTransaction(transaction2);
account.AddTransaction(transaction3);

account.Balance.Should().Be(100.0m);

可以在哪里实施

private decimal _balance;

public void AddTransaction(Transaction transaction)
{
    _balance += transaction.Amount;
}

public decimal Balance => _balance;

如你所见,class可以不用list实现。如果应用程序使用 Balance 的次数比 AddTransaction 方法多得多,则上述方法可能有效。

通过进行不知道实现的测试,您可以在不更改测试的情况下自由重构 class。

显然,您首先需要为 Balance 和 AddTransaction 方法实现 getter。现在,很容易测试 Balance。您在测试方法中创建一个或两个已知金额的交易,调用 AddTransactions 将它们添加到帐户中,然后获取 Balance 的值并将其与所有金额的总和进行比较。 要测试添加交易,您必须稍微修改您的帐户 class。我看到的选项是:

  1. 添加一个可以接受交易列表的构造函数(正如 Ethan 已经提到的)。
  2. 您可能对第一种方法有所顾虑,因为这种方法可以更好地控制帐户。如果是这样的话,您可以创建一个方法来获取帐户中的交易数量,并根据该方法测试 AddTransactions。
  3. 创建一个 GetFirstTransaction 和一个 GetLastTransaction 方法并基于它们测试您的 AddTransaction 方法。
  4. 这样做不值得,但可以创建一个 public 属性,只需要一个 getter,returns 交易列表的深层副本,你可以在你的测试方法中测试它。