State based testing is when you exercise one or many methods of an object and then assert the expected state of the object. Many test-driven developers prefer state based tests because they specify as little implementation detail as possible. Tests that specify no implementation details should continue to pass even if the implementation of the methods being tested are changed. The following state based delegation test will continue to be valid for either of the following implementations.
require 'test/unit'
class ShowPresenterTests < Test::Unit::TestCase
def test_delegation_of_name_to_employee
employee = Employee.new("Shane Harvie")
assert_equal "Shane Harvie", ShowPresenter.new(employee).name
end
end
class Employee < Struct.new(:name); end
class ShowPresenter < Struct.new(:employee)
def name
employee.name
end
end
require 'forwardable'
class ShowPresenter < Struct.new(:employee)
extend Forwardable
def_delegator :employee, :name
end
State based tests can contain stubs, but they are generally avoided where possible. State based tests are easy to spot because they rely on assertions to verify the state of the application.
Developers who generally rely on state based tests can be considered Classicists. Martin Fowler has a great article,
Mocks Aren't Stubs, that expands greatly on the ideas that are briefly mentioned here.
I do prefer tests not to be too closely coupled to implementation
ReplyDeletebut if you write granular state based tests then they can get quite coupled.
I'm mainly a state tester but I have become interested in how to use interaction testing well and BDD offers another way of looking at things. At least in the .NET scene it seems like a few people are thinking BDD will allow us to write high level behavior tests without getting them too coupled to implementation, which could prove useful.