在博文之一中我们将Order中的常量重构到了数据库的表中,也做了一些测试,貌似一切都很完美.可是...梦魔还未开始啊!我们少做了一步测试,就是rake test!
结果惨不忍睹,所有测试都是E,全部出错!提示payment_types表中找不到字段type!这个很好解决,检查test/fixtures/payment_types.yml文件,发现其中字段名称还是type,将其改为pay_type,则所有E都消失鸟.
可是噩梦还未结束!仍然有2个F!检查发现无论是在Order中还是Order控制器中动态赋予的:PaymentType.all.map {|type|type.pay_type}在rake test中统统都为nil值,而且在测试开头的setup中设置也不行!如果还原Order中的:
PAYMENT_TYPES = ["Check","Credit card","Purchase order"]
则没有问题.不太了解test背后的机制,为毛不能应用动态的值呢?还是百思不得其"姐"中...
思来想去,想要放弃又不太甘心啊!静下心来重新理一下思绪吧:
首先test测试用的是test数据库中的内容,如果正常流程执行没有问题而测试过不去的话,是不是test数据库里面有问题呢?抱着试一试的心态,用sqlite3 test.sqlite3打开test数据库,检查里面的payment_types表内容,果真没有东东啊!难怪出现上面字段都为nil的情况啊!下面的就是如何在test的数据库中添加pay_type的问题了.
首先第一次尝试:在seeds.rb中增加如下代码:
PaymentType.delete_all PaymentType.create(pay_type:'Check') PaymentType.create(pay_type:'Credit card') PaymentType.create(pay_type:'Purchase order')
运行rake db:seed,检查test数据库还是没有记录.思考发现以上代码貌似是在development上下文中执行的,也就是说它把记录添加到development.sqlite3数据库中去了啊!我们可以让其在test上下文中执行:
RAILS_ENV=test rake db:seed
再次检查test数据库,终于有内容了!但是别急着高兴哦!再次rake test还是出错,错误相同!再次查看test数据库中的内容:又被清空了.遂猜测到test的运行机制:首先清空test数据库,然后再做测试!那么解决起来就简单鸟:
首先在test/test_helper.rb中添加一个新的方法init_payment_types:
class ActiveSupport::TestCase # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. fixtures :all def init_payment_types PaymentType.delete_all PaymentType.create(pay_type:'Check') PaymentType.create(pay_type:'Credit card') PaymentType.create(pay_type:'Purchase order') end # Add more helper methods to be used by all tests here... end
然后修改test出错的控制器test类OrderControllerTest中的setup方法的block:
class OrdersControllerTest < ActionController::TestCase setup do #Order::PAYMENT_TYPES = PaymentType.all.map {|type|type.pay_type} init_payment_types @order = orders(:one) end end
再测试一下,咦怎么还是不行啊,错误依旧!?进一步检查发现:虽然setup中手动预先插入了支付方式记录,但是貌似model Order工作方式如下:在test中Order Class会首先初始化,注意这早于setup的执行;意味着这时test数据库中还是没有内容;执行到validates :pay_type,inclusion:PaymentType.types一句时会生成类似代码:
validates :pay_type,inclusion:[#空的数组]
等到以后在Order控制器测试时虽然执行了setup,但是以后的create和update测试方法的model检查用的还是一开始生成的[#空的数组],所以还是执行不通过!一种办法是在rake test之前调用RAILS_ENV=test rake db:seed;或者只有早于第一次Order Class初始化在test数据库中插入payment_types,在一番搜索后,发现可以在config/initizlizers下加入初始化ruby脚本来实现该功能:
首先在上述目录下建立新文件:make_payment_types.rb,加入以下代码:
if Rails.env == "test" PaymentType.delete_all PaymentType.create(pay_type:'Check') PaymentType.create(pay_type:'Credit card') PaymentType.create(pay_type:'Purchase order') end
我们只需要在测试试才用执行该脚本哦;或者为了不违背DRY原则,我们可以在make_payment_types.rb中这样写:
if Rails.env == "test" load 'db/seeds.rb' end
经过一番折腾,终于全部测试通过啦!但是还别急啊,这样重构总觉得哪里有问题,感觉很别扭,本猫觉(Jiao三声)着还是要重构哦!要知最后大结局请看博文之三吧! :)