Rails ActiveSupport::TestCase - 如何动态定义测试及其辅助方法?
Rails ActiveSupport::TestCase - How do I dynamically define tests together with their helper methods?
我正在为我的 Rails (5.2) 测试构建一些抽象,因为我想 运行 使用不同的参数集多次进行相同的测试。
我可以成功创建一个助手来即时生成测试 类。在我的 test_helper.rb:
中,这看起来像下面这样
class << self
def test_configs(configs: DEFAULT_CONFIGS, &block)
configs.each do |c|
Class.new(ActiveSupport::TestCase) { yield(c) }
end
end
end
我可以在任何给定的测试文件中使用这个助手,如下所示:
require 'test_helper'
class SampleTest < ActiveSupport::TestCase
test_configs do |c|
test "#{c[:name]} - something is true" do
puts "#{c[:name]}" => # Correctly outputs c[:name]
end
end
end
"#{c[:name]}"
根据从助手传递的内容 "config" 为每次迭代正确插值。到目前为止一切顺利。
我在创建一些也使用变量 c
的辅助方法时遇到问题,无论是在 test_configs
方法本身还是在单个测试文件中。
None 的以下工作 在传递给测试标题的 c
变量与测试中发生的事情之间给出一致的匹配他们自己:
# Approach 1
class SampleTest < ActiveSupport::TestCase
test_configs do |c|
def config_name
"#{c[:name]}" # => undefined local variable or method `c'
end
test "#{c[:name]} - something is true" do
puts "#{config_name}"
end
end
end
# Approach 2
class SampleTest < ActiveSupport::TestCase
test_configs do |c|
define_method("config_name") {
"#{c[:name]}"
}
test "#{c[:name]} - something is true" do
puts "#{config_name}" # => Uses only the last definition
end
end
end
# Approach 3
class << self
def test_configs(configs: DEFAULT_CONFIGS, &block)
configs.each do |c|
define_method "config_name" do # (same with def config_name)
"#{c[:name]}"
end
Class.new(ActiveSupport::TestCase) { yield(c) }
end
end
end
# => undefined local variable or method `config_name'
如何正确使用传递的变量的 "inject" 方法?
正确的方法与我的问题中的第 3 个类似,但是 yield
必须替换为 instance_eval
以便块中的代码继承新 class 我正在创建:
# test_helper.rb
class ActiveSupport::TestCase
class << self
def test_configs(configs: DEFAULT_CONFIGS, &block)
configs.each do |c|
Class.new(ActiveSupport::TestCase) {
define_singleton_method "config_title" do
"#{c[:name]}".capitalize
end
define_method "config_name" do
"#{c[:name]}"
end
instance_eval(&block)
end
end
end
end
end
# sample_test.rb
require 'test_helper'
class SampleTest < ActiveSupport::TestCase
test_configs do
test "#{config_title} - something is true" do # => Correctly invokes the class method defined above
puts "#{config_name}" # => Correctly invokes the instance method defined above
end
end
end
如您所见,还有一个区别是 class 方法必须定义才能在测试标题中使用,而实例方法必须定义才能在测试中使用。
如果必须将 c
传递给块(例如,为了在块本身内定义其他方法),instance_exec
应该是要走的路:docs.
我正在为我的 Rails (5.2) 测试构建一些抽象,因为我想 运行 使用不同的参数集多次进行相同的测试。
我可以成功创建一个助手来即时生成测试 类。在我的 test_helper.rb:
中,这看起来像下面这样class << self
def test_configs(configs: DEFAULT_CONFIGS, &block)
configs.each do |c|
Class.new(ActiveSupport::TestCase) { yield(c) }
end
end
end
我可以在任何给定的测试文件中使用这个助手,如下所示:
require 'test_helper'
class SampleTest < ActiveSupport::TestCase
test_configs do |c|
test "#{c[:name]} - something is true" do
puts "#{c[:name]}" => # Correctly outputs c[:name]
end
end
end
"#{c[:name]}"
根据从助手传递的内容 "config" 为每次迭代正确插值。到目前为止一切顺利。
我在创建一些也使用变量 c
的辅助方法时遇到问题,无论是在 test_configs
方法本身还是在单个测试文件中。
None 的以下工作 在传递给测试标题的 c
变量与测试中发生的事情之间给出一致的匹配他们自己:
# Approach 1
class SampleTest < ActiveSupport::TestCase
test_configs do |c|
def config_name
"#{c[:name]}" # => undefined local variable or method `c'
end
test "#{c[:name]} - something is true" do
puts "#{config_name}"
end
end
end
# Approach 2
class SampleTest < ActiveSupport::TestCase
test_configs do |c|
define_method("config_name") {
"#{c[:name]}"
}
test "#{c[:name]} - something is true" do
puts "#{config_name}" # => Uses only the last definition
end
end
end
# Approach 3
class << self
def test_configs(configs: DEFAULT_CONFIGS, &block)
configs.each do |c|
define_method "config_name" do # (same with def config_name)
"#{c[:name]}"
end
Class.new(ActiveSupport::TestCase) { yield(c) }
end
end
end
# => undefined local variable or method `config_name'
如何正确使用传递的变量的 "inject" 方法?
正确的方法与我的问题中的第 3 个类似,但是 yield
必须替换为 instance_eval
以便块中的代码继承新 class 我正在创建:
# test_helper.rb
class ActiveSupport::TestCase
class << self
def test_configs(configs: DEFAULT_CONFIGS, &block)
configs.each do |c|
Class.new(ActiveSupport::TestCase) {
define_singleton_method "config_title" do
"#{c[:name]}".capitalize
end
define_method "config_name" do
"#{c[:name]}"
end
instance_eval(&block)
end
end
end
end
end
# sample_test.rb
require 'test_helper'
class SampleTest < ActiveSupport::TestCase
test_configs do
test "#{config_title} - something is true" do # => Correctly invokes the class method defined above
puts "#{config_name}" # => Correctly invokes the instance method defined above
end
end
end
如您所见,还有一个区别是 class 方法必须定义才能在测试标题中使用,而实例方法必须定义才能在测试中使用。
如果必须将 c
传递给块(例如,为了在块本身内定义其他方法),instance_exec
应该是要走的路:docs.