分享

Test::Unit – Ruby单元测试框架

 liu_guoping 2015-11-22

Test::Unit – Ruby单元测试框架

介绍:

单元测试是XP的核心部分。XP是伟大的,单元测试已出现了很长一段时间,而且它是一个很好的思想。好的单元测试的关键部分不是写测试代码,而是要测试。两者有什么不同吗?当然,如果你只是写测试代码而不用它,那么你以后对代码的修改将不会得到保证。换句话说,如果你已经测试(当然你首先要写测试代码),然后经常运行它们,那么你慢慢地建立了一个好习惯,虽然你不能马上知道它的益处。

[@more@]

进入单元测试,则Ruby内的用于单元测试的框架会帮助你设计,调试和评估你的代码,而你要做的就是写测试代码并运行它。

用法:

单元测试的隐含思想是让你写一个测试方法,该方法为你的代码写些断言,然后进行测试工作。大多数这些测试方法被打包到一个测试单元中,并可在开发者需要的任何时候运行。运行的结果被收集在测试结果中并通过一些UI显示给用户。让我们先看看Test::Unit提供了哪些必需的部分。

断言:

框架的中心思想是要将断言做为期望输出的语句,也就是,“我断言这个x应该等于y”。当断言被执行时,如果它返回是正确的,不会有事发生。换句话说,如果你的断言失败,则错误信息会反馈给你,以便你返回修改直到你的断言成功。对断言的详细解释,可参考Test::Unit::Assertions

测试方法与测试模具

明显地,这些断言必须在上下文环境中被调用,而这个上下文环境知道它们,并可以用它们的pass/fail值来做些事情。同样,它也可以很方便地收集相关的测试,每个测试用一个方法表示,然后放在一个知道如何运行它们的类中。有三个原因,要将测试同它们要进行测试的代码分开存放。首先,它可使你的测试代码整洁并易于管理。其次,它允许分离测试代码,因为它们只对你有用,而对用户没用。第三,它允许你设置通用的测试模具来重复测试。

什么是测试模具?测试不存活在真空中;而是依赖于它们所要测试的代码。通常,测试集依赖于一组数据,也可称为模具。如果它们被打包在同一测试类中,它们或以共享这些数据的设置与解除,即setupteardown方法。这可去除不必要的重复,并使模具可以容易地添加其它测试。

Test::Unit::TestCase包装测试方法在容器内,并允许你很容易地为每个测试设置和解除相同测试模具。这都是通过覆写setupteardown方法来做到,它们将在每个测试方法运行前及运行后被调用。TestCase也知道如何收集你在Test::Unit::TestResult中的断言结果,然后它将报告显示给你。想写一个测试,得依循下面步骤:

l 确保Test::Unit在你的库路径上。

l 在测试脚本中请求‘test/unit’

l 创建Test::Unit::TestCase类的子类。

l 为你的类添加以"test"开头的方法。

l 在你的方法内使用断言。

l 可按需要定义setup/teardown来设置你的测试模具。

l 现在你就可以运行你的测试了。

一个相对简单的测试看起来可能是这样(setupteardown通常不用给出,它们可选的)

require 'test/unit'

class TC_MyTest < Test::Unit::TestCase

# def setup

# end

# def teardown

# end

def test_fail

assert(false, 'Assertion was false.')

end

end

测试运行器

现在,你有了测试类,但是你还需要一种方式来运行它,并观察在运行期间可能发生的任何失败。它就是Test::Unit::UI::Console::TestRunner(或是其它的,如Test::Unit::UI:GTK::TestRunner)。如果你在源文件请求了’test/unit’并运行了这个文件,则控制台测试运行器是自动被调用给你的。若是想使用其它运行器或手工管理运行器,可简单地调用它的run类方法并传递一个对象给它,这个对象应处理Test::Unit::TestSuitesuite消息。传递到你的TestCase(这个类有一个suite方法)内也这么简单。看起来一个实现应该是样的:

require 'test/unit/ui/console/testrunner'

Test::Unit::UI::Console::TestRunner.run(TC_MyTest)

测试单元

工程内的测试单元会越来越多,它终会变得在运行时缓慢。同时它也会让你得到潜在的测试失败,因为太多了你忘记了运行它。而易于管理的TestRunner可接受任何对象,只要这个对象有与Test::Unit::TestSuite相对应的suite方法。TestSuite可以依次包含其它的TestSuite或单独的测试(通常由TestSuites创建)。换句话说,你可以很容易地包装一组TestCaseTestSuite,像这样:

require 'test/unit/testsuite'

require 'tc_myfirsttests'

require 'tc_moretestsbyme'

require 'ts_anothersetoftests'

class TS_MyTests

def self.suite

suite = Test::Unit::TestSuite.new

suite << TC_MyFirstTests.suite

suite << TC_MoreTestsByMe.suite

suite << TS_AnotherSetOfTests.suite

return suite

end

end

Test::Unit::UI::Console::TestRunner.run(TS_MyTests)

现在,这还有点笨重,即使Test::Unit已经为我们做了很多,当你请求’test/unit’时自动地为你包装了这些。这是什么意思?它的意思是你应该像这个例子一样写测试案例:

require 'test/unit'

require 'tc_myfirsttests'

require 'tc_moretestsbyme'

require 'ts_anothersetoftests'

Test::Unit很聪明,它足以找到所有的ObjectSpace内的测试案例并为你将它们包装在一个单元内。然后它使用控制台运行器运行动态单元。

下面文字来自于:http://anw./ocean/show/UnitTesting

Ruby 內建 Unit Testing Framework, Test::Unit, 使用起來也蠻簡單的.
  1. 寫你的測試 class 記得從 Test::Unit::TestCase 繼承
    
    require 'test/unit'
    
    class MyFriend < Test::Unit::TestCase
      def setup
        @friends = ['dell', 'apple', 'sony']
      end
    
      def teardown
      end
    
      def test_add
        assert_instance_of(Array, @friends, "The @friends must be Array")
    
        assert_equal(3, @friends.size, "The size is not 3")
    
        @friends << 'acer'
        assert_equal(4, @friends.size, "The size is not 4")
      end
    
      def test_remove
        assert_equal(3, @friends.size, "The size is not 3")
    
        @friends.delete_if {|n| n == 'apple'}
        assert_equal(2, @friends.size, "The size is not 2")
      end
    end
    
  2. 現在有了 test class, 你會想要測試他的執行結果.
    
    require 'test/unit/ui/console/testrunner'
    
    Test::Unit::UI::Console::TestRunner.run(MyFriend)
    

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多