这是测试我的ruby类的正确方法吗?

时间:2014-10-15 04:02:15

标签: ruby unit-testing rspec tdd

我正在构建一个投资工具,并希望确保它计算正确的到期金额

以下是一些源代码:

  def maturity_amount
    if cumulative
      amount = initial_deposit * (1 + (rate_of_interest)/4 ) ** (term * 4)
      amount.round
    else
      initial_deposit
    end
  end

所以我写了一个这样的测试:

it "can calculate interest earned" do
   investment = FactoryGirl.build(:investment, initial_deposit: 250000, rate_of_interest: 9.5, cumulative: true)
   expect(investment.maturity_amount).to eq(331335)
end

你在这里看到我将结果硬编码到测试中。这会使测试变得脆弱吗?此外,我似乎无法在不更新最终结果的情况下轻松改变我给测试的输入。

那么有更好的方法来编写测试并且仍然对进行正确的计算有信心吗?我应该嘲笑吗?或者我不应该首先编写这样的测试?如果是这样,为什么?

2 个答案:

答案 0 :(得分:1)

由于您的到期日金额取决于某些条件,我认为它需要更多的测试。这是我可能会如何规范你的方法的行为(并稍微重构你的类) 我假设你的班级名为Investment

class Investment
  def maturity_amount
    if cumulative
      # kept the `.round` out here in case you had other functions
      # that may take the `ceil` or `floor` etc of `interest_earned`
      interest_earned.round
    else
      initial_deposit
    end
  end

  # Refactor out the formula into its own method so it can
  # be tested in isolation
  def interest_earned
    initial_deposit * (1 + (rate_of_interest)/4 ) ** (term * 4)
  end
end

describe Investment do
  let(:investment) { described_class.new }

  describe '#maturity_amount' do
    let(:maturity_amount) { investment.maturity_amount }

    context 'when amount is cumulative' do
      before do
        allow(investment).to receive(:cumulative).and_return(true)
        allow(investment).to receive(:interest_earned).and_return(9999.8)
      end

      it 'returns the rounded value of the cumulative amount' do
        expect(maturity_amount).to eq(10000)
      end
    end

    context 'when amount is not cumulative' do
      before do
        allow(investment).to receive(:cumulative).and_return(false)
        allow(investment).to receive(:initial_deposit).and_return(10000)
      end

      it 'returns the initial deposit' do
        expect(maturity_amount).to eq(10000)
      end
    end
  end

  describe '#interest_earned' do
    let(:interest_earned) { investment.interest_earned }
    # you may have various circumstances/edge cases where you would like to
    # test that the interest earned calculates what you would expect, and I
    # would put them in different `context` blocks, but for simplicity's sake
    # I'll just use one simple case here
    before do
      # using the Factory values from your question...
      allow(investment).to receive(:initial_deposit).and_return(250000)
      allow(investment).to receive(:rate_of_interest).and_return(9.5)
      # not sure of your default term value would be, so just use 1
      allow(investment).to receive(:term).and_return(1)
    end

    it 'calculates the interest earned' do
      # something seems a bit strange here given this passing test...
      # I assume there are other values that contribute to this calculation
      # that I'm missing
      expect(interest_earned).to eq(32436584.47265625)
    end
  end
end

答案 1 :(得分:0)

看起来不错!测试远非脆弱。如果您更改输入或算法,测试将只会失败,这正是它应该失败的条件。测试不应该有任何逻辑或元编程。

如果您没有根据输入做不同的事情,则无需使用不同的输入编写许多测试。这将增加测试套件的维护负担,而不会增加任何值。

简单就是更好。