cwninja-drunit 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +32 -0
- data/Rakefile +52 -0
- data/bin/drunit_remote +15 -0
- data/lib/drunit.rb +46 -0
- data/lib/drunit/remote_app.rb +52 -0
- data/lib/drunit/remote_test.rb +54 -0
- data/test/fake_app/fake_app.rb +13 -0
- data/test/test_helper.rb +5 -0
- data/test/unit/main_test.rb +41 -0
- metadata +64 -0
data/README.markdown
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# Distributed Ruby Unit (Testing)
|
2
|
+
|
3
|
+
A library for running tests across multiple applications from a single test case.
|
4
|
+
|
5
|
+
|
6
|
+
## Basic usage:
|
7
|
+
|
8
|
+
class MainTest < Test::Unit::TestCase
|
9
|
+
include Drunit
|
10
|
+
RemoteApp(:fake_app, FAKE_APP_PATH + "/fake_app.rb")
|
11
|
+
RemoteApp(:rails_app, RAILS_APP_PATH + "/script/runner")
|
12
|
+
|
13
|
+
def test_should_use_the_same_db
|
14
|
+
id = in_app(:fake_app){
|
15
|
+
User.create!(:name => "Some Name")
|
16
|
+
}
|
17
|
+
|
18
|
+
in_app(:rails_app, id) do |id|
|
19
|
+
assert_nothing_raised() { User.find(id) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
## Other "features"
|
25
|
+
* Automatically "Brings Up" and "Takes Down" your apps as needed. (Uses GC to tell when it's no longer needed.)
|
26
|
+
* Tracking of assertion counts.
|
27
|
+
* Beautified (a little) backtraces.
|
28
|
+
* Line number preserving between apps.
|
29
|
+
* Packed full of bugs (probably, I'm not sure).
|
30
|
+
* Packed full of 1.9 incompatibilities (I'm assuming).
|
31
|
+
* Packed full of space ninjas.
|
32
|
+
* Over 14% more awesome than a bag of chips.
|
data/Rakefile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
require 'date'
|
7
|
+
|
8
|
+
desc 'Default: run unit tests.'
|
9
|
+
task :default => :test
|
10
|
+
|
11
|
+
desc 'run tests.'
|
12
|
+
Rake::TestTask.new(:test) do |t|
|
13
|
+
t.libs << 'lib'
|
14
|
+
t.pattern = 'test/**/*_test.rb'
|
15
|
+
t.verbose = true
|
16
|
+
end
|
17
|
+
|
18
|
+
spec = Gem::Specification.new do |s|
|
19
|
+
s.name = %q{drunit}
|
20
|
+
s.version = "0.1"
|
21
|
+
s.summary = %q{A library for running tests across multiple applications from a single test case.}
|
22
|
+
s.description = %q{A library for running tests across multiple applications from a single test case.}
|
23
|
+
|
24
|
+
s.files = FileList['[A-Z]*', 'lib/**/*.rb', 'test/**/*.rb', 'rails/*']
|
25
|
+
s.executables = "drunit_remote"
|
26
|
+
s.require_path = 'lib'
|
27
|
+
s.test_files = Dir[*['test/**/*_test.rb']]
|
28
|
+
|
29
|
+
s.has_rdoc = true
|
30
|
+
s.extra_rdoc_files = ["README.markdown"]
|
31
|
+
s.rdoc_options = ['--line-numbers', '--inline-source', "--main", "README.markdown"]
|
32
|
+
|
33
|
+
s.authors = ["Tom Lea"]
|
34
|
+
s.email = %q{commits@tomlea.co.uk}
|
35
|
+
|
36
|
+
s.platform = Gem::Platform::RUBY
|
37
|
+
end
|
38
|
+
|
39
|
+
Rake::GemPackageTask.new spec do |pkg|
|
40
|
+
pkg.need_tar = true
|
41
|
+
pkg.need_zip = true
|
42
|
+
end
|
43
|
+
|
44
|
+
desc "Clean files generated by rake tasks"
|
45
|
+
task :clobber => [:clobber_rdoc, :clobber_package]
|
46
|
+
|
47
|
+
desc "Generate a gemspec file"
|
48
|
+
task :gemspec do
|
49
|
+
File.open("#{spec.name}.gemspec", 'w') do |f|
|
50
|
+
f.write spec.to_ruby
|
51
|
+
end
|
52
|
+
end
|
data/bin/drunit_remote
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), *%w[.. lib drunit remote_test])
|
4
|
+
|
5
|
+
include Drunit
|
6
|
+
require ARGV.first
|
7
|
+
|
8
|
+
DRb.start_service nil, RemoteTest.new
|
9
|
+
|
10
|
+
STDOUT.puts DRb.uri
|
11
|
+
STDOUT.reopen(STDERR)
|
12
|
+
|
13
|
+
load ARGV.shift
|
14
|
+
|
15
|
+
DRb.thread.join
|
data/lib/drunit.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
module Drunit
|
2
|
+
class RemoteError < RuntimeError
|
3
|
+
def self.name
|
4
|
+
@@name
|
5
|
+
end
|
6
|
+
|
7
|
+
def class
|
8
|
+
if type = look_up_exception
|
9
|
+
return type
|
10
|
+
else
|
11
|
+
@@name = @real_exception.to_s
|
12
|
+
super
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def look_up_exception
|
17
|
+
@real_exception.split("::").inject(Object){|node, part|
|
18
|
+
node && node.const_defined?(part) && node.const_get(part)
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module ClassMethods
|
24
|
+
def RemoteApp(name, *args)
|
25
|
+
const_set "RemoteAppFor_#{name}", RemoteApp.new(name, *args)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def in_app(name, *args, &block)
|
30
|
+
file, line, method = caller(2).first.split(":")
|
31
|
+
remote_app_for(name).run(method.gsub(/^in /, "").gsub(/[^a-zA-Z0-9_?!]/, ""), file, line.to_i, *args, &block)
|
32
|
+
ensure
|
33
|
+
remote_app_for(name).last_assertion_count.times{ add_assertion } rescue nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def remote_app_for(name)
|
37
|
+
self.class.const_get("RemoteAppFor_#{name}")
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.included(other)
|
41
|
+
other.send(:extend, ClassMethods)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
require File.join(File.dirname(__FILE__), *%w[drunit remote_app])
|
46
|
+
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'drb'
|
2
|
+
require 'ruby2ruby'
|
3
|
+
|
4
|
+
module Drunit
|
5
|
+
class RemoteApp
|
6
|
+
def initialize(name, boot = nil)
|
7
|
+
@name = name
|
8
|
+
@boot = boot
|
9
|
+
@boot ||= "#{name}/test/drunit_test_helper.rb" if File.exist? "#{name}/test/drunit_test_helper.rb"
|
10
|
+
@boot ||= "#{name}/test/test_helper.rb" if File.exist? "#{name}/test/test_helper.rb"
|
11
|
+
@remote_object = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def run(method_name, file, line, *args, &block)
|
15
|
+
raise_or_return(app.eval(block_to_source(method_name, &block), file, line, method_name, *args), method_name)
|
16
|
+
end
|
17
|
+
|
18
|
+
def last_assertion_count
|
19
|
+
app.last_assertion_count
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def raise_or_return(e, method_name)
|
24
|
+
return e unless e.is_a? Exception
|
25
|
+
if first_remote_line = e.backtrace.grep(Regexp.new(method_name)).last
|
26
|
+
index = e.backtrace.index(first_remote_line)
|
27
|
+
raise e, e.message, e.backtrace[0..index] + ["RemoteApp<#{@name}>"] + caller(0)
|
28
|
+
end
|
29
|
+
raise e
|
30
|
+
end
|
31
|
+
|
32
|
+
def start_app!
|
33
|
+
drb_server = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "bin", "drunit_remote"))
|
34
|
+
pipe = IO.popen("#{drb_server} #{@boot}")
|
35
|
+
pid = pipe.pid
|
36
|
+
url = pipe.gets.chomp
|
37
|
+
remote_object = DRbObject.new(nil, url)
|
38
|
+
ObjectSpace.define_finalizer(remote_object, proc{|id| Process.kill("KILL", pid) && Process.wait})
|
39
|
+
return remote_object
|
40
|
+
end
|
41
|
+
|
42
|
+
def app
|
43
|
+
@remote_object ||= start_app!
|
44
|
+
end
|
45
|
+
|
46
|
+
def block_to_source(method_name, &block)
|
47
|
+
m = Module.new
|
48
|
+
m.send(:define_method, method_name, &block)
|
49
|
+
Ruby2Ruby.translate(m, method_name)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'drb'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
module Drunit
|
5
|
+
class RemoteError < RuntimeError
|
6
|
+
def initialize(real_exception)
|
7
|
+
@real_exception = real_exception
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class RemoteTest
|
12
|
+
attr_reader :last_assertion_count
|
13
|
+
|
14
|
+
class TestCase
|
15
|
+
include Test::Unit::Assertions
|
16
|
+
attr_reader :assertion_count
|
17
|
+
|
18
|
+
def initialize(code, source_file, source_line, method_name)
|
19
|
+
@assertion_count = 0
|
20
|
+
@method_name = method_name
|
21
|
+
instance_eval(code, source_file, source_line)
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_assertion
|
25
|
+
@assertion_count += 1
|
26
|
+
end
|
27
|
+
|
28
|
+
def run(*args)
|
29
|
+
send(@method_name, *args)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def eval(code, source_file, source_line, method_name, *args)
|
34
|
+
test_case = TestCase.new(code, source_file, source_line, method_name)
|
35
|
+
return rewrite_exceptions{ test_case.run(*args) }
|
36
|
+
rescue Exception => e
|
37
|
+
return e
|
38
|
+
ensure
|
39
|
+
@last_assertion_count = defined?(test_case.assertion_count) ? test_case.assertion_count : 0
|
40
|
+
end
|
41
|
+
private
|
42
|
+
# We need to strib down and generalise the exceptions to prevent the integration project from having to know anything about anything.
|
43
|
+
def rewrite_exceptions
|
44
|
+
return yield
|
45
|
+
rescue Test::Unit::AssertionFailedError
|
46
|
+
raise
|
47
|
+
rescue ArgumentError => e
|
48
|
+
raise e unless e.message =~ /Anonymous modules /
|
49
|
+
raise NameError, "Const Missing", e.backtrace[3..-1]
|
50
|
+
rescue Exception => e
|
51
|
+
raise Drunit::RemoteError.new(e.class.name), e.message, e.backtrace
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[.. test_helper])
|
2
|
+
|
3
|
+
class MainTest < Test::Unit::TestCase
|
4
|
+
include Drunit
|
5
|
+
RemoteApp(:fake_app, FAKE_APP_PATH + "/fake_app.rb")
|
6
|
+
def InApp(*args, &block)
|
7
|
+
in_app(:fake_app, *args, &block)
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_should_not_raise_in_a_basic_case
|
11
|
+
InApp do
|
12
|
+
assert true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_should_raise_an_exception
|
17
|
+
assert_raise(RuntimeError) { InApp{ raise "Fail" } }
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_should_raise_an_exception_faking_its_class_name_if_we_have_never_heard_of_it
|
21
|
+
InApp{ raise SomeException, "Fooo" }
|
22
|
+
flunk "Should have raised."
|
23
|
+
rescue => e
|
24
|
+
assert_equal "SomeException", e.class.name
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_should_inject_the_fact_we_are_in_a_remote_app_into_the_backtrace
|
28
|
+
e = assert_raise(RuntimeError) { InApp{ raise "Fail" } }
|
29
|
+
assert_equal 1, e.backtrace.grep("RemoteApp<fake_app>").size
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_should_raise_the_assertion_count_when_we_assert
|
33
|
+
original_count = @_result.assertion_count
|
34
|
+
InApp{ assert true}
|
35
|
+
assert_equal original_count + 1, @_result.assertion_count
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_should_be_able_to_pass_in_simple_params
|
39
|
+
assert_equal 12, InApp(2,6){|a,b| SomeFoo.new.multiply(a, b)}
|
40
|
+
end
|
41
|
+
end
|
metadata
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cwninja-drunit
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "0.1"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tom Lea
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-02-26 00:00:00 -08:00
|
13
|
+
default_executable: drunit_remote
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: A library for running tests across multiple applications from a single test case.
|
17
|
+
email: commits@tomlea.co.uk
|
18
|
+
executables:
|
19
|
+
- drunit_remote
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.markdown
|
24
|
+
files:
|
25
|
+
- Rakefile
|
26
|
+
- README.markdown
|
27
|
+
- lib/drunit/remote_app.rb
|
28
|
+
- lib/drunit/remote_test.rb
|
29
|
+
- lib/drunit.rb
|
30
|
+
- test/fake_app/fake_app.rb
|
31
|
+
- test/test_helper.rb
|
32
|
+
- test/unit/main_test.rb
|
33
|
+
- bin/drunit_remote
|
34
|
+
has_rdoc: true
|
35
|
+
homepage:
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options:
|
38
|
+
- --line-numbers
|
39
|
+
- --inline-source
|
40
|
+
- --main
|
41
|
+
- README.markdown
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: "0"
|
49
|
+
version:
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
requirements: []
|
57
|
+
|
58
|
+
rubyforge_project:
|
59
|
+
rubygems_version: 1.2.0
|
60
|
+
signing_key:
|
61
|
+
specification_version: 2
|
62
|
+
summary: A library for running tests across multiple applications from a single test case.
|
63
|
+
test_files:
|
64
|
+
- test/unit/main_test.rb
|