There is no doubt about the need for automated tests.
They
- assure refactoring steps
- help to detect weaknesses in the implementation
- document the implemented logic
- enable the implementation of modules, even if some basic modules are still missing (mocking)
Basically tests consist of 3 steps: Arrange, Act and Assert. That means establishing the test environment (Arrange), executing the logic (Act) and verifying the expectation (Assert).
Consider a bank account with the possibility to deposit money as a simple example. The implementation in advance:
class BankAccount
attr_reader :total
def initialize(amount)
@total = amount
end
def <<(amount)
@total += amount
end
end
The test is quite simple, but is separated into 3 steps in a explicit and extensive way at this point.
Arrange
To make the test executable, the appropriate environment (necessary object etc.) has to be established. This step is pretty important for the tests quality. Poor tests create too many needless objects or even create objects, which are completely counterproductive. Accessing slow or external systems (database, file system, web), even if they add no value to the tests should be avoided too.
The test for the method « requires the object under test (subject) at least:
require 'spec_helper'
RSpec.describe BankAccount do
# *** Arrange begin ***
subject { BankAccount.new 100 }
# *** Arrange end ***
describe '#<<' do
it 'adds the passed amount to total' do
end
end
end
Act
Quite often the most simple step is executing the logic under test:
require 'spec_helper'
RSpec.describe BankAccount do
subject { BankAccount.new 100 }
describe '#<<' do
it 'adds the passed amount to total' do
# *** Act begin ***
subject << 1
# *** Act end ***
end
end
end
Assert
It is important to express the expectation in a clear and concise way, when verifying the result. This is how a good documentation by tests is done. If the expectation is hard to understand, then it is also hard to understand, what the implementation actually has to do:
require 'spec_helper'
RSpec.describe BankAccount do
subject { BankAccount.new 100 }
describe '#<<' do
it 'adds the passed amount to total' do
subject << 1
# *** Assert begin ***
expect(subject.total).to eq(101)
# *** Assert end ***
end
end
end