From bde0344daa709474e6f583d6b05c548becc0eab4 Mon Sep 17 00:00:00 2001 From: Bruno Vicenzo Date: Thu, 5 May 2022 14:48:47 -0300 Subject: [PATCH 1/9] Copy code from fretadao systems --- lib/spec.rb | 3 ++ lib/spec/support.rb | 4 ++ lib/spec/support/helpers.rb | 3 ++ lib/spec/support/helpers/result.rb | 20 ++++++++++ lib/spec/support/matchers.rb | 3 ++ lib/spec/support/matchers/result.rb | 59 +++++++++++++++++++++++++++++ spec/spec_helper.rb | 1 + 7 files changed, 93 insertions(+) create mode 100644 lib/spec.rb create mode 100644 lib/spec/support.rb create mode 100644 lib/spec/support/helpers.rb create mode 100644 lib/spec/support/helpers/result.rb create mode 100644 lib/spec/support/matchers.rb create mode 100644 lib/spec/support/matchers/result.rb diff --git a/lib/spec.rb b/lib/spec.rb new file mode 100644 index 0000000..5f5c25a --- /dev/null +++ b/lib/spec.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +require_relative 'spec/support' diff --git a/lib/spec/support.rb b/lib/spec/support.rb new file mode 100644 index 0000000..d83453d --- /dev/null +++ b/lib/spec/support.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +require_relative 'support/helpers' +require_relative 'support/matchers' diff --git a/lib/spec/support/helpers.rb b/lib/spec/support/helpers.rb new file mode 100644 index 0000000..6c90b16 --- /dev/null +++ b/lib/spec/support/helpers.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +require_relative 'helpers/result' diff --git a/lib/spec/support/helpers/result.rb b/lib/spec/support/helpers/result.rb new file mode 100644 index 0000000..a81c4f9 --- /dev/null +++ b/lib/spec/support/helpers/result.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module FServiceResultHelpers + def f_service_result(result, value = nil, type = nil) + if result == :success + FService::Result::Success.new(value, type) + else + FService::Result::Failure.new(value, type) + end + end + + def mock_service(service, result: :success, value: nil, type: nil) + service_result = f_service_result(result, value, type) + allow(service).to receive(:call).and_return(service_result) + end +end + +RSpec.configure do |config| + config.include FServiceResultHelpers +end diff --git a/lib/spec/support/matchers.rb b/lib/spec/support/matchers.rb new file mode 100644 index 0000000..6c90b16 --- /dev/null +++ b/lib/spec/support/matchers.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +require_relative 'helpers/result' diff --git a/lib/spec/support/matchers/result.rb b/lib/spec/support/matchers/result.rb new file mode 100644 index 0000000..49fae60 --- /dev/null +++ b/lib/spec/support/matchers/result.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require 'rspec/expectations' + +RSpec::Matchers.define :have_failed_with do |expected| + match do |actual| + matched = actual.is_a?(FService::Result::Failure) && actual.type == expected + + matched &&= actual.error == @expected_error if defined?(@expected_error) + + matched + end + + chain :and_error do |expected_error| + @expected_error = expected_error + end + + failure_message do |actual| + if actual.is_a?(FService::Result::Failure) + message = "expected failure's type '#{actual.type.inspect}' to be equal '#{expected.inspect}'" + if defined?(@expected_error) + message += " and error '#{actual.error.inspect}' to be " + message += @expected_error.respond_to?(:description) ? @expected_error.description : "equal '#{@expected_error.inspect}'" + end + + message + else + "result '#{actual.inspect}' is not a Failure object" + end + end +end + +RSpec::Matchers.define :have_succeed_with do |expected| + match do |actual| + matched = actual.is_a?(FService::Result::Success) && actual.type == expected + + matched &&= values_match?(@expected_value, actual.value) if defined?(@expected_value) + + matched + end + + chain :and_value do |expected_value| + @expected_value = expected_value + end + + failure_message do |actual| + if actual.is_a?(FService::Result::Success) + message = "expected success's type '#{actual.type.inspect}' to be equal '#{expected.inspect}'" + if defined?(@expected_value) + message += " and value '#{actual.value.inspect}' to be " + message += @expected_value.respond_to?(:description) ? @expected_value.description : "equal '#{@expected_value.inspect}'" + end + + message + else + "result '#{actual.inspect}' is not a Success object" + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 00470a4..3dd1030 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -7,6 +7,7 @@ require 'bundler/setup' require 'f_service' +require 'spec' RSpec.configure do |config| # Enable flags like --only-failures and --next-failure From d6f1911e66e9cd509f9a04ff2f59168681540c1d Mon Sep 17 00:00:00 2001 From: Bruno Vicenzo Date: Thu, 5 May 2022 14:54:08 -0300 Subject: [PATCH 2/9] Refactory test assertion same context level --- spec/f_service/base_spec.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/spec/f_service/base_spec.rb b/spec/f_service/base_spec.rb index 2f24155..b0fa1a0 100644 --- a/spec/f_service/base_spec.rb +++ b/spec/f_service/base_spec.rb @@ -30,11 +30,13 @@ end describe '#Check' do - subject(:response) { described_class.new.Check(:math_works) { 1 < 2 } } + context 'when block evaluates to true' do + subject(:response) { described_class.new.Check(:math_works) { 1 < 2 } } - it { expect(response).to be_successful } - it { expect(response.type).to eq(:math_works) } - it { expect(response.value!).to eq(true) } + it { expect(response).to be_successful } + it { expect(response.type).to eq(:math_works) } + it { expect(response.value!).to eq(true) } + end context 'when block evaluates to false' do subject(:response) { described_class.new.Check(:math_works) { 1 > 2 } } From bc181c6fb7aacba4aaf09cf07be1487208e96035 Mon Sep 17 00:00:00 2001 From: Bruno Vicenzo Date: Thu, 5 May 2022 14:55:55 -0300 Subject: [PATCH 3/9] Refactory test assertion same context level --- spec/f_service/result/success_spec.rb | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/spec/f_service/result/success_spec.rb b/spec/f_service/result/success_spec.rb index 02e6a50..5493da9 100644 --- a/spec/f_service/result/success_spec.rb +++ b/spec/f_service/result/success_spec.rb @@ -3,20 +3,22 @@ require 'spec_helper' RSpec.describe FService::Result::Success do - subject(:success) { described_class.new('Yay!') } + describe 'initialize' do + subject(:success) { described_class.new('Yay!') } - it { expect(success).to be_a described_class } - it { expect(success).to be_successful } - it { expect(success).not_to be_failed } - it { expect(success.value).to eq('Yay!') } - it { expect(success.type).to eq(nil) } - it { expect(success.error).to eq(nil) } - it { expect(success.value!).to eq('Yay!') } + it { expect(success).to be_a described_class } + it { expect(success).to be_successful } + it { expect(success).not_to be_failed } + it { expect(success.value).to eq('Yay!') } + it { expect(success.type).to eq(nil) } + it { expect(success.error).to eq(nil) } + it { expect(success.value!).to eq('Yay!') } - context 'when defining a type' do - subject(:success) { described_class.new('Yay!', :ok) } + context 'when defining a type' do + subject(:success) { described_class.new('Yay!', :ok) } - it { expect(success.type).to eq(:ok) } + it { expect(success.type).to eq(:ok) } + end end describe '#on_success' do @@ -132,6 +134,8 @@ end describe '#to_s' do + subject(:success) { described_class.new('Yay!') } + it { expect(success.to_s).to eq 'Success("Yay!")' } end end From 68c76a70e8848aaa6ff8c99f0c41d7877d1552cf Mon Sep 17 00:00:00 2001 From: Bruno Vicenzo Date: Thu, 5 May 2022 14:57:22 -0300 Subject: [PATCH 4/9] Refactory test assertion same context level --- spec/f_service/result/failure_spec.rb | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/spec/f_service/result/failure_spec.rb b/spec/f_service/result/failure_spec.rb index fd32310..6aa72ad 100644 --- a/spec/f_service/result/failure_spec.rb +++ b/spec/f_service/result/failure_spec.rb @@ -3,20 +3,22 @@ require 'spec_helper' RSpec.describe FService::Result::Failure do - subject(:failure) { described_class.new('Whoops!') } + describe 'initialize' do + subject(:failure) { described_class.new('Whoops!') } - it { expect(failure).to be_a described_class } - it { expect(failure).to be_failed } - it { expect(failure).not_to be_successful } - it { expect(failure.error).to eq('Whoops!') } - it { expect(failure.type).to eq(nil) } - it { expect(failure.value).to eq(nil) } - it { expect { failure.value! }.to raise_error FService::Result::Error } + it { expect(failure).to be_a described_class } + it { expect(failure).to be_failed } + it { expect(failure).not_to be_successful } + it { expect(failure.error).to eq('Whoops!') } + it { expect(failure.type).to eq(nil) } + it { expect(failure.value).to eq(nil) } + it { expect { failure.value! }.to raise_error FService::Result::Error } - context 'when defining a type' do - subject(:failure) { described_class.new('Whoops!', :error) } + context 'when defining a type' do + subject(:failure) { described_class.new('Whoops!', :error) } - it { expect(failure.type).to eq(:error) } + it { expect(failure.type).to eq(:error) } + end end describe '#on_failure' do @@ -133,6 +135,8 @@ end describe '#to_s' do + subject(:failure) { described_class.new('Whoops!') } + it { expect(failure.to_s).to eq 'Failure("Whoops!")' } end end From b77fe8871fcabb1f0e883ba5f55e4d143b3bc1b5 Mon Sep 17 00:00:00 2001 From: Bruno Vicenzo Date: Thu, 5 May 2022 15:40:28 -0300 Subject: [PATCH 5/9] Add README instructions --- README.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/README.md b/README.md index f0206f2..7240569 100644 --- a/README.md +++ b/README.md @@ -257,6 +257,55 @@ IHateEvenNumbers.call # => #, @type=:rand_int> ``` +## Testing + +We provide some helpers and matchers to make ease to test code envolving Fservice services. + +To make available in the system, in the file 'spec/spec_helper.rb' or 'spec/rails_helper.rb' + +add the folowing require: + +```rb +require 'f_service/spec' +``` + +### Mocking a result + +``` +mock_service(Uer::Create) +# => Mocks a successful result with all values nil + +mock_service(Uer::Create, result: :success) +# => Mocks a successful result with all values nil + +mock_service(Uer::Create, result: :success, type: :created) +# => Mocks a successful result with type created + +mock_service(Uer::Create, result: :success, type: :created, value: instance_spy(User)) +# => Mocks a successful result with type created and a value + +mock_service(Uer::Create, result: :failure) +# => Mocs a failure with all nil values + +mock_service(Uer::Create, result: :failure, type: :invalid_attributes) +# => Mocs a failure with a failure type + +mock_service(Uer::Create, result: :failure, type: :invalid_attributes, value: { name: ["can't be blank"] }) +# => Mocs a failure with a failure type and an error value +``` + +### Matching a result + +```rb +expect(User::Create.(name: 'Joe')).to have_succeed_with(:created) + +expect(User::Create.(name: 'Joe')).to have_succeed_with(:created).and_value(an_instance_of(User)) + +expect(User::Create.(name: nil)).to have_failed_with(:invalid_attributes) + +expect(User::Create.(name: nil)).to have_failed_with(:invalid_attributes).and_error({ name: ["can't be blank"] }) +``` + ## API Docs You can access the API docs [here](https://www.rubydoc.info/gems/f_service/). From 2fae8c16e23bfd7c74db1e39081d7a842434e06a Mon Sep 17 00:00:00 2001 From: Bruno Vicenzo Date: Thu, 5 May 2022 15:44:08 -0300 Subject: [PATCH 6/9] Add Changelog info --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f6b09d..a494c31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 --- +### Added + +- Rspec Helper mock_service; +- Rspec Matcher have_succeed_with and have_failed_with + ## 0.2.0 ### Added - Add `and_then` as alias for `then` (partially fix [#23](https://github.com/Fretadao/f_service/issues/23)). From de9382d271ec5f1d56168e634aac6b48c5f8af0c Mon Sep 17 00:00:00 2001 From: Bruno Vicenzo Date: Thu, 5 May 2022 16:22:31 -0300 Subject: [PATCH 7/9] Move to right place --- README.md | 2 +- lib/f_service/rspec.rb | 3 +++ lib/{spec => f_service/rspec}/support.rb | 0 lib/{spec => f_service/rspec}/support/helpers.rb | 0 lib/{spec => f_service/rspec}/support/helpers/result.rb | 0 lib/{spec => f_service/rspec}/support/matchers.rb | 0 lib/{spec => f_service/rspec}/support/matchers/result.rb | 0 lib/spec.rb | 3 --- spec/spec_helper.rb | 2 +- 9 files changed, 5 insertions(+), 5 deletions(-) create mode 100644 lib/f_service/rspec.rb rename lib/{spec => f_service/rspec}/support.rb (100%) rename lib/{spec => f_service/rspec}/support/helpers.rb (100%) rename lib/{spec => f_service/rspec}/support/helpers/result.rb (100%) rename lib/{spec => f_service/rspec}/support/matchers.rb (100%) rename lib/{spec => f_service/rspec}/support/matchers/result.rb (100%) delete mode 100644 lib/spec.rb diff --git a/README.md b/README.md index 7240569..caeb792 100644 --- a/README.md +++ b/README.md @@ -266,7 +266,7 @@ To make available in the system, in the file 'spec/spec_helper.rb' or 'spec/rail add the folowing require: ```rb -require 'f_service/spec' +require 'f_service/rspec' ``` ### Mocking a result diff --git a/lib/f_service/rspec.rb b/lib/f_service/rspec.rb new file mode 100644 index 0000000..eabc575 --- /dev/null +++ b/lib/f_service/rspec.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +require_relative 'rspec/support' diff --git a/lib/spec/support.rb b/lib/f_service/rspec/support.rb similarity index 100% rename from lib/spec/support.rb rename to lib/f_service/rspec/support.rb diff --git a/lib/spec/support/helpers.rb b/lib/f_service/rspec/support/helpers.rb similarity index 100% rename from lib/spec/support/helpers.rb rename to lib/f_service/rspec/support/helpers.rb diff --git a/lib/spec/support/helpers/result.rb b/lib/f_service/rspec/support/helpers/result.rb similarity index 100% rename from lib/spec/support/helpers/result.rb rename to lib/f_service/rspec/support/helpers/result.rb diff --git a/lib/spec/support/matchers.rb b/lib/f_service/rspec/support/matchers.rb similarity index 100% rename from lib/spec/support/matchers.rb rename to lib/f_service/rspec/support/matchers.rb diff --git a/lib/spec/support/matchers/result.rb b/lib/f_service/rspec/support/matchers/result.rb similarity index 100% rename from lib/spec/support/matchers/result.rb rename to lib/f_service/rspec/support/matchers/result.rb diff --git a/lib/spec.rb b/lib/spec.rb deleted file mode 100644 index 5f5c25a..0000000 --- a/lib/spec.rb +++ /dev/null @@ -1,3 +0,0 @@ -# frozen_string_literal: true - -require_relative 'spec/support' diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 3dd1030..ee551ae 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -7,7 +7,7 @@ require 'bundler/setup' require 'f_service' -require 'spec' +require 'f_service/rspec' RSpec.configure do |config| # Enable flags like --only-failures and --next-failure From 2a05dd00f7aba6dd2a2c4989aeab00bfafb429d6 Mon Sep 17 00:00:00 2001 From: Bruno Vicenzo Date: Thu, 5 May 2022 16:41:34 -0300 Subject: [PATCH 8/9] Fix - Import right file --- lib/f_service/rspec/support/matchers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/f_service/rspec/support/matchers.rb b/lib/f_service/rspec/support/matchers.rb index 6c90b16..11bbdcf 100644 --- a/lib/f_service/rspec/support/matchers.rb +++ b/lib/f_service/rspec/support/matchers.rb @@ -1,3 +1,3 @@ # frozen_string_literal: true -require_relative 'helpers/result' +require_relative 'matchers/result' From e4be6a676c931f7deacdc7014acb566b5286eb14 Mon Sep 17 00:00:00 2001 From: Bruno Vicenzo Date: Thu, 5 May 2022 17:28:11 -0300 Subject: [PATCH 9/9] Fix rubocops --- lib/f_service/rspec/support/helpers/result.rb | 3 +++ lib/f_service/rspec/support/matchers/result.rb | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/f_service/rspec/support/helpers/result.rb b/lib/f_service/rspec/support/helpers/result.rb index a81c4f9..6329174 100644 --- a/lib/f_service/rspec/support/helpers/result.rb +++ b/lib/f_service/rspec/support/helpers/result.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true +# Methods to mock a FService result from a service call. module FServiceResultHelpers + # Create an Fservice result Success or Failure. def f_service_result(result, value = nil, type = nil) if result == :success FService::Result::Success.new(value, type) @@ -9,6 +11,7 @@ def f_service_result(result, value = nil, type = nil) end end + # Mock a Fservice service call returning a result. def mock_service(service, result: :success, value: nil, type: nil) service_result = f_service_result(result, value, type) allow(service).to receive(:call).and_return(service_result) diff --git a/lib/f_service/rspec/support/matchers/result.rb b/lib/f_service/rspec/support/matchers/result.rb index 49fae60..0e7b900 100644 --- a/lib/f_service/rspec/support/matchers/result.rb +++ b/lib/f_service/rspec/support/matchers/result.rb @@ -19,8 +19,9 @@ if actual.is_a?(FService::Result::Failure) message = "expected failure's type '#{actual.type.inspect}' to be equal '#{expected.inspect}'" if defined?(@expected_error) + has_description = @expected_error.respond_to?(:description) message += " and error '#{actual.error.inspect}' to be " - message += @expected_error.respond_to?(:description) ? @expected_error.description : "equal '#{@expected_error.inspect}'" + message += has_description ? @expected_error.description : "equal '#{@expected_error.inspect}'" end message @@ -47,8 +48,9 @@ if actual.is_a?(FService::Result::Success) message = "expected success's type '#{actual.type.inspect}' to be equal '#{expected.inspect}'" if defined?(@expected_value) + has_description = @expected_value.respond_to?(:description) message += " and value '#{actual.value.inspect}' to be " - message += @expected_value.respond_to?(:description) ? @expected_value.description : "equal '#{@expected_value.inspect}'" + message += has_description ? @expected_value.description : "equal '#{@expected_value.inspect}'" end message