Google

Friday, May 16, 2008

keeping 1 assertion per testcases in RoR

I'm rewriting badly written unit test at the office.

first, using MVC for RoR, unit test mirrors models/, checking the validity of what goes into database and data types allowed. and much of what's handled in controllers/ go to functional tests. Then there are view tests that often goes into unit/ and some of full regressions in scenario based that goes into integration tests area.

the ones i had to rewrite, there were much of controllers validations, for example. and, each testcases with like two dozen assert this and assert that. so how can you tell when you run 12 testcases and out of 75 assertions 3 fails? how to you analyze and how do you put it in matrix? and, how do you know if assertion failure triggers cascade affect for the rest of assertions in testcase or not?

as tedious as it may seem, do setup and teardown repeatedly, and put one assertion per testcase. say if you put assertion for an account's email existing, in next testcase where you use same account, make a note either to yourself or on the comments that email existance check is already done and that you move on the format of the email. not if it's used for login or not, but just enter different possible email addresses, like with non-alphanumeric characters, or in localized address, or ones entered without domain, or ones that are very long.

i like the one i careated for account testing, which still has whole lot more roon to add, by the way, and i'm excited to add more testcases here, and also to build whole suite of'em ground up!


require File.dirname(__FILE__) + '/../../test_helper'

require 'test/unit'

class AccountTest < Test::Unit::TestCase
def setup
super
@account = create_testacct
end

def teardown
acct_cleanup
end

def test_new_acct_have_a_unique_username
@account = create_testacct

assert_not_nil @account.unique_username

acct_cleanup
end

def test_cannot_create_acct_with_email_not_having_domainname
assert_raise(ArgumentError,"accttest is not a valid email address.") do
@account = Account.create_by_email("accttest")
end
end

def test_cannot_create_acct_with_email_not_having_domainname2
assert_raise(ArgumentError,"accttest is not a valid email address.") do
@account = Account.create_by_email("accttest@")
end
end

def test_cannot_create_acct_with_email_having_bad_domain
assert_raise(ArgumentError,"accttest is not a valid email address.") do
@account = Account.create_by_email("accttest@testdomain")
end
end

def test_cannot_create_acct_with_email_having_only_domainname
assert_raise(ArgumentError,"accttest is not a valid email address.") do
@account = Account.create_by_email("@testdomain.com")
end
end

def test_new_acct_not_activated
@account = create_testacct
set_default_password

assert !(@account.activated?)

acct_cleanup
end

def test_activate_method_makes_new_acct_active_acct
@account = create_and_activate_testacct

assert @account.activated?

acct_cleanup
end

def test_activate_acct_without_password_fails_with_correct_error
@account = create_testacct

assert_raises(Error::HumanReadable, "You must set a password before we can activate your account!") do
@account.activate()
end

acct_cleanup
end

def test_cannot_create_acct_with_existing_email_address
@account = create_and_activate_testacct
assert_raise(AccountModule::AccountExistsError,
"There is already an account with this email address, please try a different one.") do
@account2 = create_and_activate_testacct
end

acct_cleanup
end

private
def create_testacct
@account = Account.create_by_email("accttest@localhost")
@account.save!

return @account
end

def set_default_password
@account.password = "test123"
end

def create_and_activate_testacct
@account = create_testacct
set_default_password
@account.activate()
@account.save

return @account
end

def acct_cleanup
@account.destroy
end
end