After fumbling around with Ruby for a few weeks I've fallen into a coding pattern that I'm comfortable with. When I create a new class and that class has dependencies, I add a method initialize_dependencies
that does the job of creating them. That function is then executed from the constructor.
When I write a test for this class, I actually test a subclass where the initialize_dependencies
function has been overridden and the dependencies replaced with stubs or mocks. Here is an example of such a test (with most tests and test data removed for brevity):
require "address_kit/entities/street_address"
module AddressKit
module Validation
describe FinnValidationDriver do
# Subject returns hard coded results from finn client.
subject {
Class.new(FinnValidationDriver) {
def initialize_dependencies
@client = Object.new
@client.define_singleton_method(:address_search) { |address_string|
FINN_VALIDATION_DRIVER_TEST_DATA[address_string] or []
}
end
}.new
}
it "considers an address invalid if finn returns no results" do
address = AddressKit::Entities::StreetAddress.new({
street_name: "FOOBAR",
house_number: 123
})
subject.valid?(address).must_equal false
subject.code.must_equal FinnValidationDriver::CODE_NO_RESULTS
end
it "considers an address invalid if finn returns multiple results" do
address = AddressKit::Entities::StreetAddress.new({
street_name: "FORNEBUVEIEN",
house_number: 10
})
subject.valid?(address).must_equal false
subject.code.must_equal FinnValidationDriver::CODE_NOT_SPECIFIC
end
end
end
end
FINN_VALIDATION_DRIVER_TEST_DATA = {
"FORNEBUVEIEN 10" => [
AddressKit::Entities::StreetAddress.new({
street_name: "FORNEBUVEIEN",
house_number: 10,
entrance: "A",
postal_code: 1366,
city: "LYSAKER"
}),
AddressKit::Entities::StreetAddress.new({
street_name: "FORNEBUVEIEN",
house_number: 10,
entrance: "B",
postal_code: 1366,
city: "LYSAKER"
})
],
"TORGET 12, ASKIM" => [
AddressKit::Entities::StreetAddress.new({
street_name: "TORGEIR BJØRNARAAS GATE",
house_number: 12,
postal_code: 1807,
city: "ASKIM"
}),
AddressKit::Entities::StreetAddress.new({
street_name: "TORGET",
house_number: 12,
postal_code: 1830,
city: "ASKIM"
})
]
}
This class only has one dependency, which is a client for a web service. Here I replace it with a stub returning static data.
I'm fairly new with Ruby so there are probably at least a few issues or potholes with this approach that I'm not seeing. Is there a best practice when it comes to writing classes and tests for them? Am I way off?