I Wrote a general testing file which includes a few tests.
I want to write a few files that will use those tests, each file will run specific tests (not all of them).
A test example:
class AccountBase
describe "TC_ACCOUNT" do
it "Fill info Fields" do
#test here
end
end
end
Lets call it baseTests.rb.
Now I have another file - infoTest.rb .
How can I call "Fill info Fields" from within infoTest
Thanks.
It sounds like you need Rspec's shared examples:
Shared examples on Relish,
or in the Rspec API docs
Your example might look something like:
class AccountBase
shared_examples "TC_ACCOUNT" do
it "Fill info Fields" do
#test here
end
end
end
And then you could include the shared examples in your infoTest.rb file with:
include_examples "TC_ACCOUNT"
or:
it_behaves_like "TC_ACCOUNT"
The shared example can then be written to check metadata from the context that includes it or accept parameters to its block that are passed in by the including spec, so as to change its behaviour based on which test file it's being included into.
Related
I have two tests that are very similar. In fact, both tests should produce the same results, but for different inputs. Each needs its own before block but in the interest of DRY I'd like them to share the same it block.
Is that even possible? If so, how?
Shared Examples in Rspec are designed to be used for this purpose. You can keep common it blocks inside a shared example and include them in describe or context blocks.
Simplest example of shared_examples would be,
RSpec.shared_examples "unauthorized_response_examples" do
it { expect(subject).to respond_with(403) }
it { expect(json['message']).to eq(I18n.t("unauthorized")) }
end
And inside your controller specs whenever you need to check unauthorized response you can include examples like,
...
include_examples "unauthorized_response_examples"
Also, you can pass on parameters, action names and controller names and have before(:each|:all) hooks and nested contexts or describe.
For more, you can look at rspec documentation.
Helper methods. (Excuse the horribleness of the example. Would have been better if you'd posted yours :P)
describe "soup" do
def soup_is_salty # helper method! \o/
soup.add(:meat)
soup.add(:egg)
soup.cook
soup.salty?
end
describe "with carrot" do
before(:all) do
soup.add(:carrot)
end
it "should be salty" do
soup_is_salty # get help from helper method! \o/
end
end
describe "soup with potato" do
before(:all) do
soup.add(:potato)
end
it "should be salty" do
soup_is_salty # get help from helper method! \o/
end
end
end
Take the block and create and external method
for example I have some tests that require me to login to my app. So I have a helper.rb file that I include in each spec and that contains a "login" block. Then in each test I can just call login
I have a series of RSpec tests - each one living in their own files - that all need a specific object to be ran (shop).
Since setting up the shop object is complicated, I want to have a master file that builds the shop object and then passes it to all the RSpec test files in turn. The idea is that those writing the test scripts do not need to know anything about the setup step.
I could not figure out how to bring something from the outside world into an rspec test case. I have tried variations around the lines of this:
file master.rb:
describe "Testing tests/some_test.rb" do
before :all do
#shop = some_complex_operations
end
load 'tests/some_test.rb'
end
file tests/some_test.rb:
describe 'Some feature' do
it 'should know about #shop'
expect(#shop).not_to be nil
end
end
When I run rspec master.rb then some_test.rb fails.
I know what I outlined is probably a very wrong way to go about this, but I hope at least you get the idea.
How can I implement such a thing cleanly?
What you need is a global hook.
You can create a spec_helper and add there a before all global hook. For example:
RSpec.configure do |config|
config.before(:each) do
#shop = "in case you need a fresh instance of shop each time"
end
config.before(:all) do
#shop = "in case you need a single instance (i.e. you don't modify it)"
end
end
Then you should require this helper from each of your specs. The spec_helper can store any global hooks as well as helpers, or other dependencies for your tests.
When you are writing a test, it should test one thing. shop might be a very complex object, which many objects and methods interact with, but I should guess none of them are aware of the complexity of shop - each method is interested in some aspect of shop.
Therefore I suggest that instead of building a complex object for each test, make a double of it, make it expect what's relevant, and then simply stub the rest:
describe 'Some feature' do
let(:shop) { double('shop').as_nil_object }
let(:my_object) { MyClass.new(shop: shop) }
it 'should do something awesome with shop' do
expect(shop).to receive(:awesome_data).and_return(my_data: 'is_this')
expect(my_object.do_something_awesome).to eq 'how awesome is_this?'
end
end
I'm just writing some algorithm methods that I don't want to put in a class. So I just put them in my ruby file.
But I cant figure out how to write test or more specifically use describe :xxx since I dont' have a class name to put after the main describe. Any ideas?
You can put any string after the describe statement:
describe "Something You Want To Test" do
# Your specs here
end
I want to run a given suite of tests several times - once as each of the basic types of system users. (It tests the various features that should be shared by them). More generally, I often end up wanting to run the same set of tests under different conditions.
run_as_each(user_list) do |user|
describe "When visiting the front page with #{user.name}" do
it "should see the welcome message" do
....
end
it "should be able to login" do
....
end
end
end
But this isn't working - It says my method "run_as_each" is undefined - in fact, it seems helpers can only be used inside of the actual specific tests, "it"s. So what should I do?
So what is another way I can approach this problem - specifically, to run a batch of tests for several different users, or at the least to define within a test which users it should be run for?
Have you looked into using shared example? You mentioned types of users, so something like this might work.
shared_examples "a user" do
let(:user) { described_class.new }
describe "When visiting the front page" do
it "should see the welcome message" do
....
end
it "should be able to login" do
....
end
end
end
describe UserTypeA do
it_behaves_like 'a user'
end
describe UserTypeB do
it_behaves_like 'a user'
end
I didn't run the code, so syntax errors are probable.
More from the docs
I was able to get around this problem by including a file with a namespaced module that included all the "helper" methods I needed to use for dynamic code generation. The actual test helpers, if included through the rspec config, are only loaded when the tests are being executed - they are, thus, not available to the any code that occurs outside of tests.
I'd like a very basic example of a tiny base program, that reads in two plugins and registers them. These two plugins hook into the base program in the same way in a unconflicting manner.
I'm very new to metaprogramming in any programming language for that matter, I'm not sure where to start.
i've been working on this very problem for a while now. i've tried a number of different ways to go about doing it and sought advice from a lot of people on it. i'm still not sure if what i have is 'the right way', but it works well and is easy to do.
in my case, i'm specifically looking at configuration and bringing in configuration plugins, but the principle is the same even if the terminology for mine is specific to cnfiguration.
at a very basic level, i have a Configuration class with nothing in it - it's empty. I also have a Configure method which returns the configuration class and lets you call methods on it:
# config.rb
class Configuration
end
class MySystem
def self.configure
#config ||= Configuration.new
yield(#config) if block_given?
#config
end
Dir.glob("plugins/**/*.rb").each{|f| require f}
end
MySystem.configure do |config|
config.some_method
config.some_value = "whatever"
config.test = "that thing"
end
puts "some value is: #{MySystem.configure.some_value}"
puts "test #{MySystem.configure.test}"
to get the some_method and some_value on the configuration class, I have the plugins extend the configuration object via modules:
# plugins/myconfig.rb
module MyConfiguration
attr_accessor :some_value
def some_method
puts "do stuff, here"
end
end
class Configuration
include MyConfiguration
end
and
# plugins/another.rb
module AnotherConfiguration
attr_accessor :test
end
class Configuration
include AnotherConfiguration
end
to load up the plugins, you only need one of code to look for the .rb files in a specific folder and 'require' them. this code can live anywhere as long as it's run right away when the file that contains it is loaded... i would probably put it in the class definition for MySystem or something like that to start with. maybe move it somewhere else when makes sense.
Dir.glob("plugins/**/*.rb").each{|f| require f}
run config.rb and you'll get output that looks like this:
do stuff, here
some value is: whatever
test that thing
there are a lot of options for implementing the various parts of this, but this should get you down the path.
It looks like this project may help: https://github.com/eadz/plugman
I haven't however found anything that will handle embedded (gem) dependencies however. Including Ruby files is straightforward but once your plugins start requiring other libraries then this simple model falls apart (either all the deps have to be installed with your application, or you need some other mechanism to get the plugin dependency gems into the process).