Skip to content

Commit 1c48294

Browse files
author
Alexandre Barret
committed
Create a UseCaseMock to help testing use cases when used in other classes.
1 parent 16214d5 commit 1c48294

File tree

3 files changed

+103
-0
lines changed

3 files changed

+103
-0
lines changed

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,35 @@ During the `perform` method, you should have stored the results as instance vari
9393

9494
The caller can check the success or failure of the use case by calling the `success?` and `failure?` helper methods. If the use case has had a failure, the errors will be available on the standard `errors` collection.
9595

96+
## Testing
97+
When a use case is used in another class to perform an action or query, it can be handy to use a mock instead.
98+
To do so, `require 'use_case_mock'` in your specs and use the UseCaseMock class to create the state of the use case after the perform action. This is particularly handy when you want to add errors and keep a stable use case behaviour.
99+
Adding errors to the mock will make the use case failed? but not invalid? if `perform!` is called.
100+
101+
```ruby
102+
require 'spec_helper'
103+
require 'use_case_mock'
104+
105+
RSpec.describe MyParentClass do
106+
107+
before do
108+
use_case = UseCaseMock.new(results: [])
109+
use_case.errors.add(:base, 'Could not fetch results from 3rd party API')
110+
111+
allow(MyUseCase).to receive(:perform) { use_case }
112+
end
113+
114+
describe '.upload' do
115+
it 'does something' do
116+
MyParentClass.upload('/some/random/file.txt')
117+
118+
# ...
119+
end
120+
end
121+
end
122+
123+
```
124+
96125
## Development
97126

98127
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.

lib/use_case_mock.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
require 'ostruct'
2+
3+
class UseCaseMock < OpenStruct
4+
include UseCasePattern
5+
6+
def perform
7+
self
8+
end
9+
end

spec/use_case_mock_spec.rb

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
require "spec_helper"
2+
require "use_case_mock"
3+
4+
describe UseCaseMock do
5+
let(:mock) { UseCaseMock.new(results: ['result_1', 'result_2']) }
6+
7+
describe "#perform" do
8+
context "when the including class has defined a perform method" do
9+
it "should call the perform method" do
10+
expect(UseCaseMock).to receive(:perform)
11+
UseCaseMock.perform
12+
end
13+
end
14+
15+
context "when the including class has defined a perform method and initializer" do
16+
subject(:result){ UseCaseMock.perform(number: 10) }
17+
18+
it "should call the initializer" do
19+
expect(UseCaseMock).to receive(:new).with(number: 10).and_call_original
20+
result
21+
end
22+
23+
it "should have no errors" do
24+
expect(result.errors.full_messages).to eq([])
25+
end
26+
27+
it "should return the use case object" do
28+
expect(result.class).to eq(UseCaseMock)
29+
end
30+
31+
it "returns the correct attribute readers" do
32+
expect(result.number).to eql 10
33+
end
34+
end
35+
36+
context "with a use case that generates errors" do
37+
subject(:result) { UseCaseMock.perform }
38+
39+
before do
40+
result.errors.add(:age, "can't be blank")
41+
end
42+
43+
describe "#success?" do
44+
subject(:success){ result.success? }
45+
it { expect(success).to eq(false) }
46+
end
47+
48+
describe "#failure?" do
49+
subject(:failure){ result.failure? }
50+
it { expect(failure).to eq(true) }
51+
end
52+
53+
describe "#errors" do
54+
subject(:errors){ result.errors }
55+
it { expect(errors.full_messages).to eq(["Age can't be blank"]) }
56+
end
57+
58+
describe "#perform!" do
59+
it "does not raise an error" do
60+
expect { result.perform! }.not_to raise_error(UseCasePattern::ValidationError, "Validation failed: Age can't be blank")
61+
end
62+
end
63+
end
64+
end
65+
end

0 commit comments

Comments
 (0)