testdouble / mocktail Goto Github PK
View Code? Open in Web Editor NEW๐ฅ Take your Ruby, and make it a double!
Home Page: https://rubygems.org/gems/mocktail
License: MIT License
๐ฅ Take your Ruby, and make it a double!
Home Page: https://rubygems.org/gems/mocktail
License: MIT License
I just upgraded Mocktail from 1.2.0 to 1.2.1 on a project with no other changes and started seeing this error:
Error:
ReactionEventsTest#test_reaction_added_events_are_logged:
SyntaxError: /usr/local/bundle/gems/mocktail-1.2.1/lib/mocktail/imitates_type/makes_double/declares_dry_class.rb:60: syntax error, unexpected '=', expecting ')'
->( = ((__mocktail_default_args ||...
^
/usr/local/bundle/gems/mocktail-1.2.1/lib/mocktail/imitates_type/makes_double/declares_dry_class.rb:60: syntax error, unexpected ']', expecting literal content or terminator or tSTRING_DBEG or tSTRING_DVAR
...ocktail_default_args ||= {})[:] = nil), &blk) do
The corresponding line in my test suite that this is tied to looks like:
slack_client_mock = Mocktail.of_next(Slack::Web::Client)
The way I'm getting around this is by wrapping calls to the third party Slack library in a PORO and mocking instances of said PORO, but wanted to open this issue just in case.
The gemspec mentions 2.7 as the minimum ruby version; however, running the test suite does not appear to pass (at least for me, locally) when using 2.7.4.
rake
)Tests Pass
1) Error:
VerifyTest#test_uses_a_captor_for_a_complex_arg:
ArgumentError: ArgumentError
/mocktail/lib/mocktail/handles_dry_call/validates_arguments.rb:41:in `validate'
/mocktail/lib/mocktail/handles_dry_call.rb:14:in `handle'
/mocktail/lib/mocktail/imitates_type/makes_double/declares_dry_class.rb:42:in `block (2 levels) in define_double_methods!'
/mocktail/test/safe/verify_test.rb:135:in `test_uses_a_captor_for_a_complex_arg'
61 runs, 295 assertions, 0 failures, 1 errors, 0 skips
I also ran the tests locally with ruby 3.0.1, and tests passed for me then.
I am intrigued in concept by the idea of mocktail, but I can't easily understand what it is. Ideally, I'd see a concise description of the problem, and how mocktail solves that. Perhaps a quick code example, showing before/after mocktail could help?
There's nothing about this in the README, and while there seems to be solid docs (nice work!) on implementing mocktail etc, they seem to make me get into the details before I can understand whether it's worth that effort.
I only briefly dug into the cause, but wasn't able to find it. Posting a repro here in case anybody else cares to look.
require "mocktail"
class Foobar < Sequel::Model
def name
"Bar"
end
end
foobar = Mocktail.of(Foobar)
Mocktail.stubs { foobar.name }.with { "Foobar" }
Mocktail.explain(foobar)
Run with sequel mock://sqlite <file.rb>
Output
I, [2021-11-15T02:43:07.555625 #52542] INFO -- : (0.000001s) SELECT * FROM `foobars` LIMIT 0
/usr/local/bundle/gems/mocktail-0.0.6/lib/mocktail/share/determines_matching_calls.rb:4:in `determine': stack level too deep (SystemStackError)
from /usr/local/bundle/gems/mocktail-0.0.6/lib/mocktail/handles_dry_call/fulfills_stubbing/finds_satisfaction.rb:11:in `block in find'
from /usr/local/bundle/gems/mocktail-0.0.6/lib/mocktail/handles_dry_call/fulfills_stubbing/finds_satisfaction.rb:10:in `each'
from /usr/local/bundle/gems/mocktail-0.0.6/lib/mocktail/handles_dry_call/fulfills_stubbing/finds_satisfaction.rb:10:in `find'
from /usr/local/bundle/gems/mocktail-0.0.6/lib/mocktail/handles_dry_call/fulfills_stubbing/finds_satisfaction.rb:10:in `find'
from /usr/local/bundle/gems/mocktail-0.0.6/lib/mocktail/handles_dry_call/fulfills_stubbing.rb:22:in `satisfaction'
from /usr/local/bundle/gems/mocktail-0.0.6/lib/mocktail/handles_dry_call/fulfills_stubbing.rb:12:in `fulfill'
from /usr/local/bundle/gems/mocktail-0.0.6/lib/mocktail/handles_dry_call.rb:16:in `handle'
from /usr/local/bundle/gems/mocktail-0.0.6/lib/mocktail/imitates_type/makes_double/declares_dry_class.rb:45:in `block (2 levels) in define_double_methods!'
... 9981 levels...
from /usr/local/bundle/gems/sequel-5.50.0/bin/sequel:260:in `each'
from /usr/local/bundle/gems/sequel-5.50.0/bin/sequel:260:in `<top (required)>'
from /usr/local/bundle/bin/sequel:23:in `load'
from /usr/local/bundle/bin/sequel:23:in `<main>'
After adding Mocktail and following the README instructions to configure RSpec, I receive the following error when attempting to run any tests, unless I require "mocktail"
in the spec_helper.rb
:
An error occurred while loading spec_helper.
Failure/Error: config.include Mocktail::DSL
NameError:
uninitialized constant Mocktail
I confirmed I'm also seeing the same behavior when adding Mocktail to an existing (and private) Rails application.
If that seems reasonable and expected, I can push PR that updates the README to say that it should be included, but in case I'm doing something silly, I figured I'd bring this up as an issue first.
I can also try to replicate on a fresh rails app and/or gem, if you'd like different/more easily reproducible replication steps.
First off before anything, thanks for this lovely gem! I've always been fairly frustrated with mocking libraries but this one does it really nicely.
This is more of a discussion starter than anything else, but what are your thoughts on including a Mocktail.verify_not
or something similar? (Not using #refute
since that would clash with Minitest::Assertions#refute
.)
While it's true that we can easily accomplish this with something like:
assert_raises(Mocktail::VerificationError) do
Mocktail.verify do
# ...
end
end
I just think it'd just be really nice if there was a method for this, kind of in the same Ruby spirit as Minitest having #assert
and #refute
, Rails having things like #second
, #third
, and so on.
Given a class which has matching instance and class methods, if a test incorrectly calls Mocktail.of_next
instead of Mocktail.replace
then tries to demonstrate a call to the method, this error is raised:
`stubs` & `verify` expect exactly one invocation of a mocked method, but 2 were detected.
As a result, Mocktail doesn't know which invocation to stub or verify.
(Mocktail::AmbiguousDemonstrationError)
I'd expect there to be 0 invocations detected, but even better I'd love to be told that I'm not demonstrating using anything that's been mocked yet.
Here's a basic reproduction:
ambiguous.rb:
require "mocktail"
class Fighter
def self.weapon
new.weapon
end
def weapon
"sword"
end
end
Mocktail.of_next(Fighter)
Mocktail.stubs { Fighter.weapon }.with { nil }
$ ruby ambiguous.rb
I have a method on an AR model that calls a method on an associated model and does some biz with the result. I'd like to mock it but I can't seem use a Mocktail to replace an ActiveRecord association. Y'all got thoughts?
So here's my lil example script:
# frozen_string_literal: true
require 'bundler/inline'
require 'minitest/autorun'
require 'mocktail'
gemfile(true) do
source 'https://rubygems.org'
gem 'rails', '~> 7.0.4'
gem 'sqlite3'
gem 'mocktail'
end
require 'rails/all'
database = 'development.sqlite3'
ENV['DATABASE_URL'] = "sqlite3:#{database}"
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: database)
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Schema.define do
create_table :posts, force: true do |t|
end
create_table :comments, force: true do |t|
t.integer :post_id
end
end
class Post < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :post
end
class MocktailTest < ActiveSupport::TestCase
include Mocktail::DSL
test "associating a mocktail" do
post = Mocktail.of(Post)
Comment.new(post: post)
end
end
which when ran hits me with a:
Minitest::UnexpectedError: NoMethodError: undefined method `primary_key' for #<Class for mocktail of Post:0x0000000106e3b4b0>
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/reflection.rb:317:in `primary_key'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/reflection.rb:744:in `association_primary_key'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/associations/belongs_to_association.rb:130:in `primary_key'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/associations/belongs_to_association.rb:122:in `replace_keys'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/associations/belongs_to_association.rb:93:in `replace'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/associations/singular_association.rb:19:in `writer'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/associations/builder/association.rb:112:in `post='
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activemodel-7.0.4.3/lib/active_model/attribute_assignment.rb:49:in `public_send'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activemodel-7.0.4.3/lib/active_model/attribute_assignment.rb:49:in `_assign_attribute'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/attribute_assignment.rb:21:in `block in _assign_attributes'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/attribute_assignment.rb:13:in `each'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/attribute_assignment.rb:13:in `_assign_attributes'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activemodel-7.0.4.3/lib/active_model/attribute_assignment.rb:34:in `assign_attributes'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/core.rb:468:in `initialize'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/inheritance.rb:75:in `new'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/inheritance.rb:75:in `new'
/Users/dazmin/RubymineProjects/mocktail_rails_test/mocktail_rails_test.rb:42:in `block in <class:MocktailTest>'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/reflection.rb:317:in `primary_key'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/reflection.rb:744:in `association_primary_key'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/associations/belongs_to_association.rb:130:in `primary_key'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/associations/belongs_to_association.rb:122:in `replace_keys'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/associations/belongs_to_association.rb:93:in `replace'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/associations/singular_association.rb:19:in `writer'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/associations/builder/association.rb:112:in `post='
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activemodel-7.0.4.3/lib/active_model/attribute_assignment.rb:49:in `public_send'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activemodel-7.0.4.3/lib/active_model/attribute_assignment.rb:49:in `_assign_attribute'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/attribute_assignment.rb:21:in `block in _assign_attributes'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/attribute_assignment.rb:13:in `each'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/attribute_assignment.rb:13:in `_assign_attributes'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activemodel-7.0.4.3/lib/active_model/attribute_assignment.rb:34:in `assign_attributes'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/core.rb:468:in `initialize'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/inheritance.rb:75:in `new'
/Users/dazmin/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/activerecord-7.0.4.3/lib/active_record/inheritance.rb:75:in `new'
/Users/dazmin/RubymineProjects/mocktail_rails_test/mocktail_rails_test.rb:42:in `block in <class:MocktailTest>'
Process finished with exit code 1
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.