在单元测试松散类型的语言中,是否应该检查方法的返回类型?

时间:2018-10-18 16:04:28

标签: javascript python ruby unit-testing

在Java等强类型语言中,由于返回类型与方法签名不匹配,因此代码无法编译,因此无需显式检查返回的对象的类型。例如当期望整数时,您不能返回布尔值。

在松散类型的语言(如Ruby,JavaScript,Python等)中,可以返回任何内容。编写检查方法返回的对象类型的单元测试是否有意义?我认为,这将确保在期望布尔值的地方返回布尔值。

是否甚至有必要在下面进行单元测试?

============================

尝试Ruby示例:

first_module.rb:

module FirstModule
  TypeA = Struct.new(
    :prop1,
    :prop2)

  self.create_type_a
    TypeA.new(
      'prop1Val',
      'prop2Val')
  end
end

type_a_repository.rb:

module TypeARepository
  def self.function_to_test
    FirstModule.create_type_a  # This will return TypeA object
  end
end

type_a_repository_spec.rb:

RSpec.describe '' do
  describe '' do
    before do
      allow(FirstModule).to receive(:create_type_a)
          .and_return(FirstModule.create_type_a)
    end

    it '' do
      result = TypeARepository.function_to_test
      expect(result).to be_a(FirstModule::TypeA) # is this necessary?
    end
  end
end

1 个答案:

答案 0 :(得分:6)

如果您使用programming by contract,那么答案通常是“否”,只要返回值符合预期的标准(通常是很松散的),您就不会抱怨。

例如:

# Adds together zero or more integer values and returns the sum
def sum(*numbers)
  numbers.inject(0,:+)
end

在测试时,您将执行以下操作:

assert_equal 0, sum
assert_equal 1, sum(1)
assert_equal 0, sum(1, -1)

现在提供非整数值会怎样?

sum('1')
# => Exception: String can't be coerced into Integer

原始合同未将其指定为有效用例,因此有例外情况是必要的。如果要扩展范围:

# Adds together zero or more numerical values and returns the sum
def sum(*numbers)
  numbers.map(&:to_i).inject(0,:+)
end

现在您可以将非整数值加在一起:

assert_equal 6, sum(1, 2.0, '3')

请注意,只要结果通过了断言测试,您就会一直满意。在Ruby 6.06"6"中,它们都是不同的,不相等的,因此不必担心输入错误的类型。

在其他语言中可能并非如此,因此您可能需要更具体地了解结果。重要的是,如果可以的话,请避免进行文字测试,而应按预期使用结果 。例如:

assert_equal "this is amazing", "this is " + amazing_string_result

只要amazing_string_result中出现的任何内容都可以附加到字符串上,并且结果匹配,这是可接受的响应。

当您希望使用文字truefalse而不是像1这样的 truthful 值时,这通常会起作用:

assert_true some_method?(:value)

如果返回的是真实但非文字型true值,则合约被破坏并且失败。

请记住,您可以拥有无​​限数量的偏执狂。您确定自己的值正确累加了吗?

assert_equal 6, 1 + 2 + 3
assert_equal 6, 6
assert_equal 6, '6'.to_i
assert_true true

在某些时候,您不再测试代码,而是在执行该代码的编程语言或硬件上运行回归测试,如果您为您的代码。

最佳单元测试:

  • 通过清楚地描述输入和输出的期望,演示应如何使用代码。
  • 在与解决的问题相关的任何和所有边界条件下识别并验证行为。
  • 说明以错误的方式使用代码时必须明确禁止的错误模式。
  • 避免演示所有无法使用代码的无限方式。