Testing for Failure
Learn how to do failure-path testing in unit tests.
Failure-path testing
Failure is always a possibility, so we need to test for it. We prefer to do failure-path testing in unit tests rather than end-to-end tests. Success requires the entire system to work in concert. A failure response can usually be isolated to one component. That said, it’s often useful to have one end-to-end failure test, especially in cases where the failure is easily usable and visible to a typical user.
We haven’t yet learned about the tools that will allow us to fake failure. That requires a mock object package (see Using Test Doubles as Mocks and Stubs). But in this case, it’s not hard to create a real failure by adding a validation that we can then not fulfill.
Let’s first see what an end-to-end failure test might look like by illustrating what would happen if we allow a user to create a project without a name:
class CreatesProject attr_accessor :name, :project, :task_string def initialize(name: "", task_string: "") @name = name @task_string = task_string end def build self.project = Project.new(name: name) project.tasks = convert_string_to_tasks project end def create build project.save end def convert_string_to_tasks task_string.split("\n").map do |one_task| title, size_string = one_task.split(":") Task.new(title: title, size: size_as_integer(size_string)) end end def size_as_integer(size_string) return 1 if size_string.blank? [size_string.to_i, 1].max end end
This test is similar to the original feature test, except that the name field is “filled in” with an empty string. We could not include that line, but it’s better to explicitly show ...