Используя Rspec, как я могу протестировать метод, который вызывает метод из другого класса в ruby

#ruby #rspec

#рубиновый #rspec

Вопрос:

В моем классе транзакций есть метод ‘balance’, который вызывает метод ‘balance_after’ из моего класса Account. Я хотел бы провести тест, в котором я мог бы проверить, вызывается ли метод ‘balance_after’ с помощью метода ‘balance’. Я новичок как в ruby, так и в тестировании, поэтому я ценю любые рекомендации! Я использую simple-cov для получения своего покрытия, и я хотел бы достичь 100%, если это возможно. Надеюсь, я предоставил достаточно информации. Заранее спасибо!

 Failures:

  1) Transaction#balance checks balance
     Failure/Error: @account.balance_after(self)
     
     NoMethodError:
       undefined method `balance_after' for :account:Symbol
     # ./lib/transaction.rb:11:in `balance'
     # ./spec/transaction_spec.rb:19:in `block (3 levels) in <top (required)>'

Finished in 0.04089 seconds (files took 0.87223 seconds to load)
10 examples, 1 failure

Failed examples:

rspec ./spec/transaction_spec.rb:18 # Transaction#balance checks balance


COVERAGE:  98.55% -- 68/69 lines in 4 files

 ---------- -------------------- ------- -------- --------- 
| coverage | file               | lines | missed | missing |
 ---------- -------------------- ------- -------- --------- 
|  90.91%  | lib/transaction.rb | 11    | 1      | 16      |
 ---------- -------------------- ------- -------- --------- 
 

Мой класс транзакций

 class Transaction
  attr_reader :amount, :account, :timestamp

  def initialize(amount, account)
    @amount = amount
    @account = account
    @timestamp = Time.now.strftime("%d/%m/%Y")
  end

  def balance
    @account.balance_after(self)
  end

  def formate
    @amount > 0 ? (puts "#{@timestamp}|| #{@amount} ||  ||  #{balance}")
    : (puts "#{@timestamp}||  || #{@amount.abs}  ||  #{balance}")
  end
end
 

Мой класс учетной записи

 require_relative 'transaction'

class Account
  attr_reader :balance, :transactions

  HEADER = 'date || credit || debit || balance'

  def initialize
    @balance = 0
    @transactions = []
  end

  def deposit(amount)
    @balance  = amount
    @transactions << Transaction.new(amount, self)
  end

  def withdraw(amount)
    @balance -= amount
    @transactions << Transaction.new(-amount, self)
  end

  def balance_after(transaction)
    index = @transactions.find_index(transaction)
    @transactions[0..index].map(amp;:amount).sum
  end

  def print_statement
    puts HEADER
    @transactions.reverse.map(amp;:formate)
  end
end
 

Моя спецификация транзакции

 require 'transaction'

describe Transaction do
  let(:transaction) { Transaction.new(:amount, :account) }
  let(:timestamp) { Time.now.strftime('%d/%m/%Y') }

  describe '#initilalize' do
    it 'validates class' do
      expect(transaction).to be_a Transaction
    end

    it 'stores dates' do
      expect(transaction.timestamp).to eq timestamp
    end
  end

  describe '#balance' do
    it 'checks balance' do
      expect(transaction.balance).to eq true
    end
  end
end
 

Ответ №1:

Вы должны правильно вызвать метод. Transaction.new принимает сумму, предположительно число, и какой-то balance_after определенный объект Account. Вы дали ему два символа.

 describe Transaction do
  let(:account) { Account.new }
  let(:amount) { 1.23 }
  let(:transaction) { Transaction.new(amount, account) }
  let(:timestamp) { Time.now.strftime('%d/%m/%Y') }
 

Затем убедитесь, что он возвращает то, что вы ожидаете. balance не возвращает true или false, он возвращает баланс. В частности, это просто переход к account.balance_after(transaction) , так что проверьте это.

   describe '#balance' do
    it 'checks balance' do
      expect(transaction.balance).to eq account.balance_after(transaction)
    end
  end
 

Это может показаться циклическим, но это всего лишь интеграционный тест. account.balance_after будет проходить модульное тестирование в рамках тестов учетной записи. Здесь нет необходимости повторять эти тесты.

Комментарии:

1. Привет, Шверн, спасибо за помощь! Это получило еще некоторое покрытие, что прекрасно, но некоторые строки все еще отсутствуют, по-видимому, поэтому я предполагаю, что это будет решено, как только я протестирую метод formate в классе Transaction?. Вы упомянули, что метод balance не нужен, потому что он должен быть протестирован в классе Account . Будет ли это применимо к моему методу форматирования в транзакциях, потому что у меня есть print_statement в моем классе Account? Еще раз спасибо!

2. @byronmac Вам не нужно проводить тщательное тестирование Transaction#balance , потому что это просто оболочка, Accountt#balance_after и это лучше описано в тестах Account#balance_after . Вам нужно протестировать Transaction#formate , потому что это весь код внутри Transaction . Посмотрите «интеграционный тест» против «модульного теста».

3. @byronmac Кстати, код в formate может быть простым puts "#{@timestamp}|| || #{@amount.abs} || #{balance}" . Абсолютное значение числа одинаково, независимо от того, положительное оно или отрицательное.