T

TestUnit - 使用 Ruby 编写测试代码 (1/3)

2025-06-08

TestUnit - 使用 Ruby 编写测试代码 (1/3)

迷你系列

学习的序幕
我正在培训我的下属如何编写测试代码,因为我们需要提高 ExamPro 的代码覆盖率。上周日,我快速整理了关于 TestUnit、MiniTest 和 RSpec 的三份指南。为什么是这三份?我相信,通过变化学习,才能获得完整的知识。

我认为我应该“按原样”在 DEV.to 文章上发布这三篇文章,否则我会忘记它们,它们最终会被放到我的“转储”文件夹中,再也不会被看到。

附言:我之前针对每篇指南都写过挑战。不知道大家是否感兴趣。请告诉我大家的反馈,如果感兴趣的话,请在下方留言。如果有人感兴趣的话,我会找时间发布。

测试单元

TestUnit 是一个标准的 Ruby 库。
有了标准的 Ruby 库,您无需安装 gem,因为它已经包含在语言中了。

使用TestUnit最简单的例子如下。

require "test/unit/assertions"
include Test::Unit::Assertions

hello = 'world'

assert_equal 'world', hello, "hello function should return 'world'"
Enter fullscreen mode Exit fullscreen mode

断言函数

assert_equal是众多断言函数之一。
所有测试库都包含断言函数,用于断言
某些操作是否通过。断言就是你的“测试”。

以下是 TestUnit 中所有断言函数的列表。
实际应用中,你会用到其中的一些断言函数。

assert
assert_block
assert_boolean
assert_compare
assert_const_defined
assert_empty
assert_equal
assert_fail_assertion
assert_false
assert_in_delta
assert_in_epsilon
assert_include
assert_instance_of
assert_kind_of
assert_match
assert_nil
assert_no_match
assert_not_const_defined
assert_not_empty
assert_not_equal
assert_not_in_delta
assert_not_in_epsilon
assert_not_include
assert_not_match
assert_not_nil
assert_not_predicate
assert_not_respond_to
assert_not_same
assert_not_send
assert_nothing_raised
assert_nothing_thrown
assert_operator
assert_path_exist
assert_path_not_exist
assert_predicate
assert_raise
assert_raise_kind_of
assert_raise_message
assert_raises
assert_respond_to
assert_same
assert_send
assert_throw
assert_throws
assert_true
build_message
flunk
Enter fullscreen mode Exit fullscreen mode

断言与失败

最基本的断言函数是assertflunk

函数签名定义了函数的输入和输出。
您可以在您使用的语言和库的技术文档中找到函数签名。让我们看一下 'assert 和
的函数签名,它们在RubyDocs中定义
flunk

断言

这是函数签名assert

#assert(boolean, message = nil) ⇒ Object
Enter fullscreen mode Exit fullscreen mode

这里我们可以看到assert输入需要两个参数:

  1. boolean - 必填
  2. 消息 - 可选

并输出一个Object

这就是我们使用这个函数的方法

# simple.rb
require "test/unit/assertions"
include Test::Unit::Assertions

x = true

assert x, "x should pass"
Enter fullscreen mode Exit fullscreen mode

不及格

这是函数签名flunk

#flunk(message = "Flunked") ⇒ Object
Enter fullscreen mode Exit fullscreen mode

这里我们可以看到flunk输入需要一个参数:

  1. 消息 - 如果没有提供值,则默认为“Flunked”

并输出一个Object

这就是我们使用这个函数的方法

# flunk.rb
require "test/unit/assertions"
include Test::Unit::Assertions

flunk "throw a failure message"
Enter fullscreen mode Exit fullscreen mode

的目的flunk是当你的测试总是失败时。
你可能找不到实际的效用flunk

如何用 TestUnit 正确编写测试

上面的示例是使用 TestUnit 的最少代码行数,但这不是正确的方法。
正确的方法是创建一个单独的文件。
这个新的测试文件将包含我们想要测试的代码,并且我们需要创建一个 TestCase 类来编写测试函数。

Hello World 测试用例

我们将在其自己的文件中创建一个名为的简单类hello.rb
该类将有一个名为的类方法,self.hello该方法将返回一个字符串。

# hello.rb
class Hello
  def self.world
    'world2'
  end
end
Enter fullscreen mode Exit fullscreen mode

我们将创建一个名为 的新文件。hello_test.rb
请注意,我们为文件名赋予了确切的名称,并将_test其附加到末尾。
稍后你会发现,当你有更多测试文件时,由于自动化工具的原因,你需要遵循这个惯例。

# hello_test.rb
require "test/unit"
require_relative './hello'

class HelloTest < Test::Unit::TestCase
  def test_world
    assert_equal 'world', Hello.world, "Hello.world should return a string called 'world'"
  end

  def test_flunk
    flunk "You shall not pass"
  end
end
Enter fullscreen mode Exit fullscreen mode

我们定义的类并非普通的类,而是一种领域特定语言 (DSL)。DSL
是指将代码的行为改变为语言中的语言。Ruby
语言是一种可塑性极强的语言,因此编写 DSL 非常容易。Ruby
社区在提到 DSL 时,经常说代码是“魔法”。DSL
的规则并不总是清晰的,这很容易导致混淆。

该类HelloTest的扩展Test::Unit::TestCase,正是将这个类变成 DSL 的“魔法”。
例如,当执行此文件时。

ruby hello_test.rb
Enter fullscreen mode Exit fullscreen mode

它将输出测试结果。
它将执行HelloTest类中以 开头的每个实例函数test_

  1. 测试世界
  2. 测试_flunk

如果实例函数没有使用 来命名,test_那么它将无法运行。
这是该 DSL 规则的一部分。

关于 TestUnit 的思考

TestUnit并不是 Ruby 中唯一的测试框架,因为我们还有MiniTestRspec
这些其他测试框架各有优缺点,但功能相似。

TestUnit是古老而简单的测试框架。

在接下来的讲座中,我们将探讨这两者MiniTest并了解Rspec
权衡之处。

所有框架都会被使用,很难说哪个最常用
,这取决于团队的偏好。

代码

# flunk.rb
require "test/unit/assertions"
include Test::Unit::Assertions
flunk "throw a failure message"
view raw flunk.rb hosted with ❤ by GitHub
# flunk.rb
require "test/unit/assertions"
include Test::Unit::Assertions
flunk "throw a failure message"
view raw flunk.rb hosted with ❤ by GitHub
# flunk.rb
require "test/unit/assertions"
include Test::Unit::Assertions
flunk "throw a failure message"
view raw flunk.rb hosted with ❤ by GitHub
class Hello
def self.world
'world2'
end
end
view raw hello.rb hosted with ❤ by GitHub
class Hello
def self.world
'world2'
end
end
view raw hello.rb hosted with ❤ by GitHub
class Hello
def self.world
'world2'
end
end
view raw hello.rb hosted with ❤ by GitHub
require "test/unit"
require_relative './hello'
class HelloTest < Test::Unit::TestCase
def test_world
assert_equal 'world', Hello.world, "Hello.world should return a string called 'world'"
end
def test_flunk
flunk "You shall not pass"
end
end
view raw hello_test.rb hosted with ❤ by GitHub
require "test/unit"
require_relative './hello'
class HelloTest < Test::Unit::TestCase
def test_world
assert_equal 'world', Hello.world, "Hello.world should return a string called 'world'"
end
def test_flunk
flunk "You shall not pass"
end
end
view raw hello_test.rb hosted with ❤ by GitHub
require "test/unit"
require_relative './hello'
class HelloTest < Test::Unit::TestCase
def test_world
assert_equal 'world', Hello.world, "Hello.world should return a string called 'world'"
end
def test_flunk
flunk "You shall not pass"
end
end
view raw hello_test.rb hosted with ❤ by GitHub
require "test/unit/assertions"
include Test::Unit::Assertions
x = true
assert x, "x should pass"
view raw simple.rb hosted with ❤ by GitHub
require "test/unit/assertions"
include Test::Unit::Assertions
x = true
assert x, "x should pass"
view raw simple.rb hosted with ❤ by GitHub
require "test/unit/assertions"
include Test::Unit::Assertions
x = true
assert x, "x should pass"
view raw simple.rb hosted with ❤ by GitHub

参考

https://stackoverflow.com/questions/12317921/why-undefined-method-assert-equal-is-thrown-even-after-requiring-test-unit
https://apidock.com/ruby/Test/Unit/Assertions
https://www.rubydoc.info/gems/test-unit/2.3.0/Test/Unit/Assertions
https://stackoverflow.com/questions/6515333/how-do-i-execute-a-single-test-using-ruby-test-unit
https://mattbrictson.com/minitest-and-rails

鏂囩珷鏉ユ簮锛�https://dev.to/exampro/testunit-writing-test-code-in-ruby-part-1-of-3-44m2
PREV
Vercel 与 Heroku 作为初学者如何部署 Web 应用程序?
NEXT
我推荐一些免费的 YouTube 频道来帮助你通过 AWS / Azure 认证☁️