RSpec - Testing ActiveRecord addins


#1

I wish to test a small library that I have written. The module
resides in a file in ./lib. It is loaded in the application via a a
file in ./config/initializers that contains the following code:

require ‘hll_audit_stamps’
ActiveRecord::Base
include ActiveRecord::HLLAuditStamps
end

My questions are really procedural in nature. What do I put at the
top of my spec file to load an ActiveRecord instance containing the
custom module? Or, do I put the code given above into
spec_helper.rb?

I am really only interested in the actions of the module so I would
like to create a test model instance (Mytable) inside the spec
rather than create a dummy model in app/models. How do you do this
without connecting to an underlying database? I am unfamiliar with
mocks, although this seems to be the case for one. Nonetheless, am
am uncertain how a mock would inherit the necessary characteristics
from the module that I am testing?

I would appreciate guidance here.

Sincerely,


*** E-Mail is NOT a SECURE channel ***
James B. Byrne mailto:removed_email_address@domain.invalid
Harte & Lyne Limited http://www.harte-lyne.ca
9 Brockley Drive vox: +1 905 561 1241
Hamilton, Ontario fax: +1 905 561 0757
Canada L8E 3C3


#2

James B. Byrne wrote:

am uncertain how a mock would inherit the necessary characteristics
from the module that I am testing?

I would appreciate guidance here.

Sincerely,

Hi James,
From the looks of it you may want to move your module into a plugin and
then have it’s own set of specs. Doing this may make your life easier
in running specs in the fashion you are wanting to. In the past I have
done just this and have used the in-memory sqlite3 adapter with some
dummy AR classes, just as you have explained. In your plugin’s
spec_helper put something like this:

ActiveRecord::Base.establish_connection(:adapter => “sqlite3”, :dbfile
=> “:memory:”)

def setup_db
ActiveRecord::Schema.define(:version => 1) do
create_table :vehicles do |t|
t.string :type, :name
t.integer :dealership_id
end
create_table :dealerships do |t|
t.string :name
end
end
end

def teardown_db
ActiveRecord::Base.connection.tables.each do |table|
ActiveRecord::Base.connection.drop_table(table)
end
end

setup_db

class Vehicle < ActiveRecord::Base

end

class Dealership < ActiveRecord::Base

end

You can then use the dummy AR classes in your specs with an in-memory
DB.

I hope that helps,

Ben


#3

Ben M. wrote:

You can then use the dummy AR classes in your specs with an in-memory
DB.

I hope that helps,

Ben

Oh, yes. very much. Especially this example.

def setup_db
ActiveRecord::Schema.define(:version => 1) do

Have you, or anyone reading this, had any experience with the nulldb gem
as an alternative to in memory sqlite3?


#4

(Sorry if this is double-posted, I was having trouble with joining the
list)

If you want an easy way to test ActiveRecord extensions, check out
acts_as_fu: http://github.com/nakajima/acts_as_fu. It makes generating
ActiveRecord models dead simple.

Pat


#5

James B. wrote:

Oh, yes. very much. Especially this example.

def setup_db
ActiveRecord::Schema.define(:version => 1) do

Have you, or anyone reading this, had any experience with the nulldb gem
as an alternative to in memory sqlite3?

I used nulldb on my last project and I had a lot of success with it.
Using nulldb comes with tradeoffs though and in this case I would just
use sqlite. Unless the project and spec suite is large disconnecting
the DB may not be worth the effort.

-Ben


#6

Pat N. wrote:

(Sorry if this is double-posted, I was having trouble with joining the
list)

If you want an easy way to test ActiveRecord extensions, check out
acts_as_fu: http://github.com/nakajima/acts_as_fu. It makes generating
ActiveRecord models dead simple.

Pat

Very slick. I’ll be using this next time. :slight_smile:

-Ben


#7

Pat N. wrote:

(Sorry if this is double-posted, I was having trouble with joining the
list)

If you want an easy way to test ActiveRecord extensions, check out
acts_as_fu: http://github.com/nakajima/acts_as_fu. It makes generating
ActiveRecord models dead simple.

Pat

This seems to be just what the behaviourist ordered… I am going to
try this out for my present situation.


#8

Pat N. wrote:

If you want an easy way to test ActiveRecord extensions, check out
acts_as_fu: http://github.com/nakajima/acts_as_fu. It makes generating
ActiveRecord models dead simple.

This seems to work very well. However, I am causing myself a problem
with the logger and I could use some clarification on what is happening
so that I can fix it.

I created a custom logger to format the log output into syslog style.
So, in environment.rb I have this:

Customize logger - ‘require “syslog_formatter”’

config.logger = RAILS_DEFAULT_LOGGER = Logger.new(config.log_path)
config.logger.formatter = SyslogFormatter.new
config.logger.level = Logger::INFO # DEBUG, WARN, ERROR, FATAL

and lib/syslog_formatter.rb has this:

Configure custom logger used in all environments

class SyslogFormatter
def call(level, time, program, message)
l_time = time.strftime("%b %d %H:%M:%S")
l_process = “rails[#{$PID}]”
l_host = Socket.gethostname.split(’.’)[0]
l_user = @current_user if defined?(@current_user)
l_text = (String === message ? message :
message.inspect).gsub(/\n/, ‘’).strip
“#{l_time} #{l_host} #{l_process} #{l_text} #{l_user}\n”
end
end

and when I run rake spec I see this:

NameError in ‘Role should create a new instance given valid attributes’
undefined local variable or method logger' for #<Spec::Rails::Example::ModelExampleGroup::Subclass_4:0x2ad081fa0998> /usr/lib64/ruby/gems/1.8/gems/actionpack-2.2.2/lib/action_controller/test_process.rb:471:inmethod_missing’
/home/byrnejb/Software/Development/Projects/proforma.git/spec/spec_helper.rb:25:

Which is explicitly related to this code in spec_helper.rb:

Custom Logger

config.before(:each) do
full_example_description = “#{self.class.description}
#{@method_name}”
logger.info(
“\n\n#{full_example_description}\n#{’-’ *
(full_example_description.length)}”)
end

Do I just comment this out or is there something else I should do, short
of disabling my own custom logger, to get this to work?


#9

Pat N. wrote:

If you want an easy way to test ActiveRecord extensions, check out
acts_as_fu: http://github.com/nakajima/acts_as_fu. It makes generating
ActiveRecord models dead simple.

Perhaps I misunderstood what this gem is supposed to provide but when I
call create! on an object produced by ActsASFu::build_model then I get a
method missing error. If I call create instead then I get a private
method exception. Since what I am testing is a library that links into
the create method this behaviour is problematic.

Other than this show stopper (for this situation) the gem seems to be
quite user/tester friendly and useful.


#10

James B. wrote:

and when I run rake spec I see this:

NameError in ‘Role should create a new instance given valid attributes’
undefined local variable or method logger' for #<Spec::Rails::Example::ModelExampleGroup::Subclass_4:0x2ad081fa0998> /usr/lib64/ruby/gems/1.8/gems/actionpack-2.2.2/lib/action_controller/test_process.rb:471:inmethod_missing’
/home/byrnejb/Software/Development/Projects/proforma.git/spec/spec_helper.rb:25:

Which is explicitly related to this code in spec_helper.rb:

Custom Logger

config.before(:each) do
full_example_description = “#{self.class.description}
#{@method_name}”
logger.info(
“\n\n#{full_example_description}\n#{’-’ *
(full_example_description.length)}”)
end

If I comment out my own custom logger in environment.rb this error
remains nonetheless. I have not run spec before this in this project so
I have no baseline to work from.


#11

James,

Can you show me how you’re trying to use ActsAsFu?

Pat


#12

After taking another look, I think you may be able to do something
like this to test your logger:
https://gist.github.com/3c55cbec990f283c5399

Let me know if that works.

Pat


#13

So, in acts_as_fu, I actually set the ActiveRecord logger to just log
to a StringIO that you can inspect by calling ActsAsFu.log. That’s not
going to fly for your project though, so let me give the ability to
set your own. It’ll be committed soon.

  • Pat

#14

Pat N. wrote:

After taking another look, I think you may be able to do something
like this to test your logger:
https://gist.github.com/3c55cbec990f283c5399

I am not trying to test my custom logger. That part has worked for a
few weeks now.

What is happening is that RSpec is blowing up at its own logger code in
the default spec_helper.rb file. This happens whether or not ActAsFu is
installed and whether or not my custom logger is commented out in
environment.rb


#15

Pat N. wrote:

James,

Can you show me how you’re trying to use ActsAsFu?

Pat

Not easily, because I removed the code. When I get a moment I will
reset it and post here. It will be later today.


#16

Glad it works. Just so you know, you can get created_at and updated_at
by calling #timestamps:

require 'rubygems'
require 'acts_as_fu'
require 'spec'

describe "timestamps" do
  before(:each) do
    build_model(:people) { timestamps }
    @person = Person.create!
  end

  it "adds created_at" do
    @person.created_at.should_not be_nil
  end

  it "adds updated_at" do
    @person.updated_at.should_not be_nil
  end
end

Pat


#17

James B. wrote:

Pat N. wrote:

James,

Can you show me how you’re trying to use ActsAsFu?

Pat

Not easily, because I removed the code. When I get a moment I will
reset it and post here. It will be later today.

Here is what I have. FYI once I removed the custom logger from
spec_helper.rb everything worked just fine thereafter.

hll_audit_stamps_spec.rb

require File.expand_path(File.dirname(FILE) + ‘/…/spec_helper’)

describe “Builds a Model with custom magic columns” do
before(:all) do
build_model :magiks do
string :description
# these are Rails’ own magic columns
datetime :created_at
datetime :created_on
datetime :updated_at
datetime :updated_on
# these are our custom magic columns
ActiveRecord::Base::HLL_AUDIT_COLUMNS.each do |magic_column|
string magic_column if /._by\z/.match(magic_column)
datetime magic_column if /.
_(at|on)\z/.match(magic_column)
end
end
@my_mage = Magik.new
@my_mage.save!
end

control - make sure the default behaviour is preserved

it “should set Rails created_at” do
@my_mage.created_at.should_not be_nil
puts @my_mage.created_at
end

it “should set Rails created_on” do
@my_mage.created_on.should_not be_nil
puts @my_mage.created_on
end


#18

James B. wrote:

What is happening is that RSpec is blowing up at its own logger code in
the default spec_helper.rb file. This happens whether or not ActAsFu is
installed and whether or not my custom logger is commented out in
environment.rb

I poked at this a bit and hit upon the problem. As distributed,
spec_helper.rb says this:

config.before(:each) do
full_example_description = “#{self.class.description}
#{@method_name}”
logger.info(
“\n\n#{full_example_description}\n#{’-’ *
(full_example_description.length)}”)
end

The fix is to prefix logger with Rails:: thus:

config.before(:each) do
full_example_description = “#{self.class.description}
#{@method_name}”
Rails::logger.info(
“\n\n#{full_example_description}\n#{’-’ *
(full_example_description.length)}”)
end

I have one other difficulty when running this on MS-WinXPpro under
cygwin. The newline character seems to have no effect. I can force it
to behave locally by adding a \r in front of each \n but, obviously,
that will have unfortunate consequences on *nix.

Suggestions welcome.


#19

James B. wrote:

I have one other difficulty when running this on MS-WinXPpro under
cygwin. The newline character seems to have no effect. I can force it
to behave locally by adding a \r in front of each \n but, obviously,
that will have unfortunate consequences on *nix.

Actually, that technique does not seem to work either. A ^M is inserted
into the og file, but it has no evident effect.