简体   繁体   English

Ruby中的异步单元测试

[英]Asynchronous Unit Tests in Ruby

I'm testing some javascript libraries I've built by using ruby's harmony . 我正在测试一些使用ruby's 和谐建立的javascript库。 Everything is working perfectly except AJAX calls — does anyone have any ideas how to achieve this? 除AJAX调用外,其他所有功能均正常运行-是否有人对如何实现此目标有任何想法?

My code looks something like this (I'm using RightJS ): 我的代码看起来像这样(我正在使用RightJS ):

my.js my.js

function makerequest(argument) {
    new Xhr('http://mysite.com/some/jsonp'),{
        jsonp: true,
        params: {something: argument},
        onSuccess: function() {
            // Calls a function defined outside my library
            parse_response(this.json)
        }
    }).send()
}

test_makerequest.rb test_makerequest.rb

require 'rubygems'
require 'harmony'
require 'test/unit'
require 'shoulda'

class RequestTest < Test::Unit::TestCase
    context "The requesty thing" do
        setup do
            @page = Harmony::Page.new
            @page.load(File.expand_path('js/my.js'))
        end

        should "get stuff from mysite.com" do
            # Here I need to define a 'parse_response' which this
            # should section will wait for and then do an 'assert'
            # on the results.
            results = callback_to_get_results_from__make_request
            @page.execute('make_request("an argument")')
            assert results == {'foo' => 'bar'}
        end
    end
end

So yeah, my question is, how should I assign results above such that I can get the results of the async callback? 所以,是的,我的问题是,我应该怎么分配results上面,这样我可以得到异步回调的结果吗?

Async calls are generally problematic with JS unit testing. 异步调用通常在JS单元测试中会出现问题。 I've solved it in the past by making the XHR calls effectively synchronous by blocking the main thread until the XHR call succeeds. 过去,通过阻塞主线程直到XHR调用成功,使XHR调用有效地同步,从而解决了该问题。 How to do this varies depending on your framework, and I'm unfamiliar with Harmony and RightJS. 如何执行此操作取决于您的框架,并且我对Harmony和RightJS不熟悉。 However, the logic would look something like this: 但是,逻辑看起来像这样:

  1. Override your XHR method so that it maintains a lock/mutex. 覆盖您的XHR方法,使其保持锁定/互斥。 The lock can be a simple boolean. 锁可以是一个简单的布尔值。 When any XHR is in process, the lock will be true , when no XHR is in process the lock will be false . 当有任何XHR进行中时,锁定将为true ;当没有XHR进行中时,锁定将为false
  2. In your test, before you run your assertion, add a loop that executes your XHR and then waits until the lock clears. 在测试中,在运行断言之前,添加一个执行XHR的循环,然后等待直到锁被清除。
  3. Once the loop finishes, you'll be sure the XHR has completed, and you can run your assertion. 循环结束后,您将确保XHR已完成,并且可以运行断言。

The intent of this approach is to avoid modifying your code, which would invalidate your tests. 这种方法的目的是避免修改您的代码,这会使您的测试无效。 Unfortunately, this also means you can't test the return value itself, but I think this will be a caveat of any strategy that doesn't modify your code. 不幸的是,这也意味着您无法测试返回值本身,但是我认为这将是任何不修改代码的策略的警告。

Another approach would be to actually run your tests asynchronously--ie. 另一种方法是实际异步运行测试,即 attach your assertion to the onSuccess callback using AOP. 使用AOP将您的断言附加到onSuccess回调。 However, many testing suites don't play nicely with asynchronous tests, since the setup of one test may be starting before the teardown of the previous test (ie. because the previous test is still waiting for the async call to return). 但是,许多测试套件不能很好地与异步测试配合使用,因为一个测试的设置可能在上一个测试的拆除之前开始(即,因为前一个测试仍在等待异步调用返回)。

One last approach would be to mock all asynchronous calls. 最后一种方法是模拟所有异步调用。 Ie. 就是 just override XHR and have your test assert that it was called with the right arguments. 只需覆盖XHR并让您的测试断言已使用正确的参数调用了它。 I might favor this approach if I have integration tests that do go through the whole async stack. 如果我的集成测试确实通过了整个异步堆栈,那么我可能会喜欢这种方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM