My background is Java and I am new to Ruby. I saw a mocking/stubbing framework called Mocka. I saw this example test method:
require 'test/unit'
require 'mocha/test_unit'
class MiscExampleTest < Test::Unit::TestCase
# ...
def test_mocking_an_instance_method_on_a_real_object
product = Product.new
product.expects(:save).returns(true)
assert product.save
end
#...
end
What mechanism was used to "automatically" create a mock object of Person class (or object)? Not sure what to Google for.
If it was something like this
product = mock(Product.new)
I'd easily get it.
Thank You! :)
in general, this is referred to as "monkey patching".
ruby has the concept of open classes, so at runtime you can mess around with it.
in the specific case of mocha, i assume that it is this piece of code here: https://github.com/freerange/mocha/blob/a7bc1b53ace895503b4b5d4915382aead4632e3e/lib/mocha/api.rb#L18-L22
Related
I am trying to create some data driven API tests using Test::Unit for ruby. The eventual intention is to read a series of test cases in from a .csv file. In looking for something that would be the equivalent of #dataprovider for testng, I found a class called Data which looks like exactly what I need.
http://www.rubydoc.info/github/test-unit/test-unit/Test/Unit/Data/ClassMethods
However, when I tried to create a test case to try to get it working, I get an error saying
"initial_test.rb:4:in <class:InitialTest>': undefined methoddata' for InitialTest:Class (NoMethodError)
"
code I was running:
require "test/unit"
class InitialTest < Test::Unit::TestCase
data("true" => [true],
"false" => [false])
def test_true_is_true(data)
value = data
assert(false, "FAIL!")
end
end
I can't seem to find any mention of the Data class outside of the documentation. Has anyone used this class? Am I missing something?
I'm not familiar with this module in particular, but since data is defined as an instance method on Test::Unit::Data and Test::Unit::Data is a Module, this works:
class YourTest < Test::Unit::TestCase
include Test::Unit::Data
data(…)
end
This said, you're going to want to take a closer look at the docs you linked since your example usage is looking like copy-pasta.
Turns out that the problem was that I was using an older version of Ruby that did not include the class I was trying to use. Updating to a newer version solved the problem.
I'm using ActiveRecord with Sinatra instead of Rails, and I want to use fixtures in my tests. The documentation for ActiveRecord's FixtureSet says that you have to use fixture_path to tell it where the fixture files are:
placed in the directory appointed by ActiveSupport::TestCase.fixture_path=(path)
How can I write to that setting? I tried #fixture_path and ##fixture_path, but both of them left the value nil when FixtureSet tried to read it.
Here's the only thing I could get to work, but it can't possibly be right:
# test_helper.rb
require_relative '../app'
require 'minitest/autorun'
require 'active_record'
ActiveRecord::Base.establish_connection(:test)
#Set up fixtures and such
class ActiveSupport::TestCase
include ActiveRecord::TestFixtures
include ActiveRecord::TestFixtures::ClassMethods
class << self
def fixtures(*fixture_set_names)
self.fixture_path = 'test/fixtures'
super *fixture_set_names
end
end
self.use_transactional_fixtures = true
self.use_instantiated_fixtures = false
end
The full source code is posted as a small demo project for ActiveRecord and Sinatra.
I tried to leave this as a comment on your answer, but it got too long so I thought I might as put it in an answer.
The reason #fixture_path and ##fixture_path didn't work is that fixture_path is an ActiveSupport class attribute, which is like a Ruby attr_accessor except it's defined as a singleton method on the class. You can see where the fixture_path attribute is defined with class_attribute :fixture_path in the ActiveRecord::TestFixtures module source.
Class attributes are part of ActiveSupport and not native to Ruby. You can read more about them in the Active Support Core Extensions Rails Guide and in the API docs, and see how class_attribute works in the Rails source. As you can see,
the value is stored in the instance variable "##{name}" (e.g. #fixture_path), but that happens inside a singleton method, which means it's an instance variable on the singleton class and you can only access it from within the singleton class.
That's all a little bit moot, though, because the point of attributes (and feel free to disregard this if it's old news to you) is that they allow you to keep instance variables private and change your implementation without breaking code that subclasses or includes your code. When an attribute reader or writer exists, you should always use it instead of accessing the instance variable directly, because at some point the implementation might change and the attribute methods could be replaced by methods with more complex logic, and accessing the instance variable directly will no longer produce the same results as using the attribute reader and writer.
As you discovered, you need to use self.fixture_path = instead of fixture_path = because in the latter case Ruby assumes you want to assign to a local variable.
I can't believe I didn't see this, but I didn't. I had to use self, just like the settings for transactional fixtures and instantiated fixtures.
# test_helper.rb
require_relative '../app'
require 'minitest/autorun'
require 'active_record'
ActiveRecord::Base.establish_connection(:test)
#Set up fixtures and such
class ActiveSupport::TestCase
include ActiveRecord::TestFixtures
include ActiveRecord::TestFixtures::ClassMethods
self.fixture_path = 'test/fixtures'
self.use_transactional_fixtures = true
self.use_instantiated_fixtures = false
end
The trick is understanding the meaning of self in a class definition; it refers to the class, not an instance of the class. I guess when I'm monkey patching ActiveSupport::TestCase, that's the only way to set a class variable. For some reason #fixture_path and ##fixture_path don't work.
I have to write code for an homework and I wish to do TDD from the start.
The homework consists of one ruby file with methods in it, no class.
All examples I find on the Internet test against classes. How could I test the following method?
homework.rb
#!/usr/bin/env ruby
def count_words(str)
# SOME CODE HERE
end
There is an auto-grading system that take one ruby file with the methods defined for the homework as an input. So, I have to write my tests in a separate file (test_homework.rb) or comment out my test before submitting (which I found counter productive...).
How will I test the count_words method using Test:Unit?
Do something like this:
require File.join(File.expand_path(File.dirname(__FILE__)), 'homework.rb')
require "test/unit"
class TestWordCounter < Test::Unit::TestCase
def test_count_words
assert_equal 3, count_words("one two three")
end
end
I'm currently refactoring a whole load of cucumber tests to use a "Page Object" pattern, but I'm having a lot of problems using the RSpec matchers.
The existing step I have is as follows:
Then /^I should (not )?see the following alerts:$/ do |negate, alerts|
expectation = negate ? :should_not : :should
within(ALERT_TABLE_ID) do
alerts.hashes.each do |alert|
page.send(expectation, have_content(alert["Original ID"]))
end
end
end
My refactored step is:
Then /^I should (not )?see the following alerts:$/ do |negate, alerts|
expectation = negate ? :should_not : :should
#alert_reporting_panel = AlertReportingPanel.new(Capybara.current_session)
#alert_reporting_panel.verify_contents expectation, alerts
end
And my Panel Object is:
class AlertReportingPanel
def initialize(session)
#session = session
end
def verify_contents(expectation, alerts)
#session.within(ALERT_TABLE_ID) do
alerts.hashes.each do |alert|
#session.send(expectation, have_content(alert["Original ID"]))
end
end
end
end
Unfortunately, I get undefined method 'have_contents' for #<AlertReportingPanel:0x3f0faf8> (NoMethodError).
I have tried adding require 'rspec' to the top of the class and also tried fully qualifying the have-content method thus: Capybara::RSpecMatchers::HaveMatcher.have_content, but I just get uninitialized constant Capybara::RSpecMatchers (NameError).
I'm pretty new to Ruby and I'm sure this is trivial to fix... but I just can't seem to work it out for myself.
Please help. Thankyou.
This was a while back so I'm guessing you may have your answer by now but here goes.
You need to include the necessary modules in order bring in and have access to the likes of *have_content*. So your Panel Object would look like:
class AlertReportingPanel
include Capybara::DSL
include Capybara::Node::Matchers
include RSpec::Matchers
def initialize... etc
Instead of writing your own Page Object system you could try using SitePrism
I'm a little biased (I wrote that gem) but it might make life easier for you.
I encountered a problem when trying to test a module with Test::Unit. What I used to do is this:
my_module.rb:
class MyModule
def my_func
5 # return some value
end
end
test_my_module.rb:
require 'test/unit'
require 'my_module'
class TestMyModule < Unit::Test::TestCase
include MyModule
def test_my_func
assert_equal(5, my_func) # test the output value given the input params
end
end
Now the problem is, if my_module declares an initialize method, it gets included in the test class and this causes a bunch of problems since Test::Unit seems to override/generate an initialize method. So I'm wondering what is the best way to test a module?
I'm also wondering wether my module should become a class at this point since the initialize method is made for initializing the state of something. Opinions?
Thanks in advance !
Including an initialize method in a module feels very wrong to me, so I'd rethink that at the very least.
To answer your question about testing this as a module more directly, though, I would create a new, empty class, include your module in it, create an instance of that class, and then test against that instance:
class TestClass
include MyModule
end
class TestMyModule < Unit::Test::TestCase
def setup
#instance = TestClass.new
end
def test_my_func
assert_equal(5, #instance.my_func) # test the output value given the input params
end
end
Yeah, your initialize should definitely suggest that you're going towards a class. A module in ruby often feels like an interface in other languages, as long as you implement some basic things when you include the module you'll get a lot for free.
Enumerable is a great example, as long as you define [] and each when you include Enumerable you suddenly get pop, push, etc.
So my gut feeling about testing modules is that you should probably be testing classes that include the module rather than testing the module itself unless the module is designed to not be included in anything, it's simply a code storage mechanism.