liveunit 0.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.
- checksums.yaml +7 -0
- data/.editorconfig +18 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +14 -0
- data/LICENSE +21 -0
- data/README.md +93 -0
- data/lib/liveunit.rb +91 -0
- data/lib/liveunit/evaluator.rb +81 -0
- data/lib/liveunit/loader.rb +21 -0
- data/lib/liveunit/print_reporter.rb +18 -0
- data/lib/liveunit/reporter.rb +28 -0
- data/lib/liveunit/testcase.rb +88 -0
- data/liveunit.gemspec +23 -0
- data/spec/README.md +8 -0
- data/spec/fixture.rb +32 -0
- data/spec/livetest/test_fixture.rb +16 -0
- data/spec/liveunit/evaluator_spec.rb +59 -0
- data/spec/liveunit/liveunit_spec.rb +32 -0
- data/spec/spec_helper.rb +4 -0
- metadata +118 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: b96000301a521657a5e4b992d250c36cddc730ef
|
|
4
|
+
data.tar.gz: 8d6f9e073f1df38e909c5d3ffddd762e11487439
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 5420ce45c866f5dad307fc99cee4570b50fab5c94eab181998dd4d7bf54cb4dcf87d10c0b744871504ec81fa5a6f4b0efc1c637ec47f32f13a7559242be787cf
|
|
7
|
+
data.tar.gz: e025028fb0070a44b7656cc23013707fec02d3e544c0f5e05ff527b13aedbfa112e4e3df25271b6f5e6c4c51c9dc84faec0e25c86b9a6ce2e65c59e445ecc515
|
data/.editorconfig
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# EditorConfig helps developers define and maintain consistent
|
|
2
|
+
# coding styles between different editors and IDEs
|
|
3
|
+
# editorconfig.org
|
|
4
|
+
|
|
5
|
+
root = true
|
|
6
|
+
|
|
7
|
+
[*]
|
|
8
|
+
|
|
9
|
+
indent_style = space
|
|
10
|
+
indent_size = 2
|
|
11
|
+
|
|
12
|
+
end_of_line = lf
|
|
13
|
+
charset = utf-8
|
|
14
|
+
trim_trailing_whitespace = true
|
|
15
|
+
insert_final_newline = true
|
|
16
|
+
|
|
17
|
+
[*.md]
|
|
18
|
+
trim_trailing_whitespace = false
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) <2015> <Zisis Maras - contact@zisismaras.me>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# LiveUnit
|
|
2
|
+
|
|
3
|
+
Example implementation to test my experiment on live unit testing.
|
|
4
|
+
Check the blog post here.
|
|
5
|
+
|
|
6
|
+
##Installing
|
|
7
|
+
```ruby
|
|
8
|
+
gem install liveunit
|
|
9
|
+
```
|
|
10
|
+
##Using
|
|
11
|
+
Include the module and place the evaluate_me method call in the entry point of your object(eg. the `initialize` method)
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
require 'liveunit'
|
|
15
|
+
|
|
16
|
+
class Example
|
|
17
|
+
include LiveUnit
|
|
18
|
+
def initialize
|
|
19
|
+
evaluate_me #!
|
|
20
|
+
@myvar = 15
|
|
21
|
+
end
|
|
22
|
+
def calculate(num)
|
|
23
|
+
num + 10
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
ex = Example.new
|
|
28
|
+
puts ex.calculate(40)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Then let's create a test for our calculate method in a `livetest/test_example.rb` file:
|
|
32
|
+
```ruby
|
|
33
|
+
require 'liveunit/testcase'
|
|
34
|
+
|
|
35
|
+
class TestExample < LiveUnit::TestCase
|
|
36
|
+
#doomed to fail
|
|
37
|
+
def test_calculate
|
|
38
|
+
msg "Result should be greater than 400 when @myvar==15"
|
|
39
|
+
assert_equal(15, state[:@myvar])
|
|
40
|
+
assert_operator myreturn, :>=, 400
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Run the program and you should see this :
|
|
46
|
+
```
|
|
47
|
+
Failure : TestExample#test_calculate
|
|
48
|
+
Message : Result should be greater than 400 when @myvar==15
|
|
49
|
+
Expected 50 to be >= 400.
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Features/Problems
|
|
53
|
+
The minitest's assertion system is used so most assert operations should work.
|
|
54
|
+
Autoloading and discovering is quite dumb so certain conventions must be followed:
|
|
55
|
+
|
|
56
|
+
1. Test files should be placed in a /livetest folder in the program's root directory.
|
|
57
|
+
2. Test file name should be in a format of `test_objectname.rb`.
|
|
58
|
+
3. Unit test suite has to be in a format of `class TestObjectName < LiveUnit::TestCase`
|
|
59
|
+
4. Unit test method should be named `def test_method_name`
|
|
60
|
+
|
|
61
|
+
It has not been tested with more complex things like rack applications or anything that actually matters, only simple plain ruby programs.
|
|
62
|
+
Runtime overhead is significant.
|
|
63
|
+
|
|
64
|
+
## Creating custom reporters
|
|
65
|
+
By default a reporter that writes to stdout will be used but it can be easily changed.
|
|
66
|
+
Let's create a reporter that writes to a log file, just subclass `LiveUnit::Reporter` and overwrite the `report` method.
|
|
67
|
+
The `report` method gets executed after each test and the results are available in the `results` method.
|
|
68
|
+
```ruby
|
|
69
|
+
require 'logger'
|
|
70
|
+
require 'liveunit/reporter'
|
|
71
|
+
|
|
72
|
+
class MyReporter < LiveUnit::Reporter
|
|
73
|
+
def initialize
|
|
74
|
+
@logger = Logger.new('logs')
|
|
75
|
+
super
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def report
|
|
79
|
+
results.each do |re|
|
|
80
|
+
@logger.error("Case : #{re[:case]} Failed.")
|
|
81
|
+
@logger.error("Message : #{re[:msg]}")
|
|
82
|
+
@logger.error("Enviroment : #{re[:env]}")
|
|
83
|
+
@logger.error("Expectation : #{re[:expectation]}")
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
```
|
|
88
|
+
then just pass it to the evaluate_me method : `evaluate_me(MyReporter)`
|
|
89
|
+
|
|
90
|
+
## Final Notice
|
|
91
|
+
Make sure you also read the blog post if you are interested.
|
|
92
|
+
This is not meant to be used in anything serious(it can't anyway)
|
|
93
|
+
It is just an experimental testing tool and will be probably die soon.
|
data/lib/liveunit.rb
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
require "after_do"
|
|
2
|
+
require_relative "liveunit/evaluator.rb"
|
|
3
|
+
require_relative "liveunit/loader.rb"
|
|
4
|
+
require_relative "liveunit/print_reporter.rb"
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
#Core parent module, everything lives inside it
|
|
8
|
+
module LiveUnit
|
|
9
|
+
extend self
|
|
10
|
+
##
|
|
11
|
+
#inject the required liveunit's methods when the module is included
|
|
12
|
+
def self.included(klass)
|
|
13
|
+
unless klass.instance_methods.include?(:evaluator)
|
|
14
|
+
body = Proc.new { |reporter=LiveUnit::PrintReporter|
|
|
15
|
+
@_liveunit_evaluator = LiveUnit::Evaluator.new(self)
|
|
16
|
+
if self.methods.select{|m| m.match(/^liveunit/)}.empty?
|
|
17
|
+
LiveUnit.track_methods(self, first_pass=true)
|
|
18
|
+
else
|
|
19
|
+
LiveUnit.track_methods(self, first_pass=false)
|
|
20
|
+
end
|
|
21
|
+
@_liveunit_reporter = @_liveunit_evaluator.create_reporter(klass, reporter)
|
|
22
|
+
LiveUnit::Loader.new.require_directory("./livetest")
|
|
23
|
+
}
|
|
24
|
+
klass.send(:define_method, :evaluate_me, body)
|
|
25
|
+
body = Proc.new { @_liveunit_evaluator }
|
|
26
|
+
klass.send(:define_method, :evaluator, body)
|
|
27
|
+
body = Proc.new { @_liveunit_reporter }
|
|
28
|
+
klass.send(:define_method, :reporter, body)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
##
|
|
33
|
+
#tracks all the object's methods
|
|
34
|
+
#if we have already modified the class, don't redefine again and just create the callbacks
|
|
35
|
+
def track_methods(obj, first_pass)
|
|
36
|
+
my_methods = obj.class.instance_methods(false)
|
|
37
|
+
my_methods.delete(:evaluate_me)
|
|
38
|
+
my_methods.delete(:evaluator)
|
|
39
|
+
my_methods.delete(:reporter)
|
|
40
|
+
my_methods.delete(:loader)
|
|
41
|
+
if first_pass
|
|
42
|
+
my_methods.each do |m|
|
|
43
|
+
redefine(obj, m)
|
|
44
|
+
create_callbacks_for(obj, m)
|
|
45
|
+
end
|
|
46
|
+
else
|
|
47
|
+
my_methods.each do |m|
|
|
48
|
+
create_callbacks_for(obj, m)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
##
|
|
55
|
+
#we alias the method and then wrap it as proc we can keep track of the returned value
|
|
56
|
+
def redefine(obj, meth)
|
|
57
|
+
obj.class.class_eval { alias_method "liveunit_#{meth}".to_sym, meth }
|
|
58
|
+
obj.class.class_eval <<-END_EVAL, __FILE__, __LINE__ + 1
|
|
59
|
+
def #{meth}(*args)
|
|
60
|
+
method_proc = self.method("liveunit_#{meth}".to_sym).to_proc
|
|
61
|
+
@liveunit_#{meth} = method_proc.call(*args)
|
|
62
|
+
#@liveunit_#{meth}_binding = method_proc.binding
|
|
63
|
+
@_liveunit_snapshot = @_liveunit_evaluator.liveunit_snapshot("#{meth}")
|
|
64
|
+
@liveunit_#{meth}
|
|
65
|
+
end
|
|
66
|
+
END_EVAL
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
##
|
|
70
|
+
#creates <evaluate> and <report> callbacks to be run after the method has finished
|
|
71
|
+
def create_callbacks_for(obj, meth)
|
|
72
|
+
obj.class.extend AfterDo
|
|
73
|
+
obj.class.after "#{meth.to_sym}" do
|
|
74
|
+
snapshot = obj.instance_variable_get("@_liveunit_snapshot")
|
|
75
|
+
obj.instance_variable_get("@_liveunit_evaluator").evaluate(snapshot)
|
|
76
|
+
obj.instance_variable_get("@_liveunit_reporter").report
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
#replace the eval
|
|
83
|
+
|
|
84
|
+
#body_proc = Proc.new { |*args|
|
|
85
|
+
#method_proc = obj.class.method("liveunit_#{meth}".to_sym).to_proc
|
|
86
|
+
#instance_variable_set("@liveunit_#{meth}".to_sym, method_proc.call(*args))
|
|
87
|
+
#instance_variable_set("@liveunit_#{meth}_snapshot".to_sym, @_liveunit_evaluator.liveunit_snapshot)
|
|
88
|
+
##instance_variable_set("@liveunit_#{meth}_binding".to_sym, method_proc.binding)
|
|
89
|
+
# instance_variable_get("@liveunit_#{meth}".to_sym)
|
|
90
|
+
#}
|
|
91
|
+
#obj.class.send(:define_method, "#{meth}".to_sym, body_proc)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
module LiveUnit
|
|
2
|
+
##
|
|
3
|
+
#core evaluator class, gets instantiated when the module is included
|
|
4
|
+
class Evaluator
|
|
5
|
+
|
|
6
|
+
def initialize(obj)
|
|
7
|
+
@obj = obj
|
|
8
|
+
end
|
|
9
|
+
##
|
|
10
|
+
#this will be run as a callback after every method we want to evaluate has finished,
|
|
11
|
+
#uses the snapshot taken, runs the corresponding test file and stores the results
|
|
12
|
+
def evaluate(snapshot)
|
|
13
|
+
unit, suite, obj_env, myreturn = snapshot
|
|
14
|
+
test = "test_#{unit}"
|
|
15
|
+
if Module.const_defined?("Test#{suite}")
|
|
16
|
+
test_class = Module.const_get("Test#{suite}").new(obj_env, @obj.clone, myreturn)
|
|
17
|
+
test_class.send(test)
|
|
18
|
+
unless test_class.passed?
|
|
19
|
+
@obj.reporter.liveunit_results.push(
|
|
20
|
+
:case => "#{test_class.class}##{test}",
|
|
21
|
+
:msg => test_class.msg,
|
|
22
|
+
:expectation => test_class.result_msg,
|
|
23
|
+
:env => obj_env
|
|
24
|
+
)
|
|
25
|
+
@obj.reporter.liveunit_fails += 1
|
|
26
|
+
else
|
|
27
|
+
@obj.reporter.liveunit_passes += 1
|
|
28
|
+
end
|
|
29
|
+
@obj.reporter.liveunit_assertions += 1
|
|
30
|
+
test_class.passed?
|
|
31
|
+
else
|
|
32
|
+
true
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
##
|
|
37
|
+
#captures the state that will be passed later to <evaluate>
|
|
38
|
+
def liveunit_snapshot(unit)
|
|
39
|
+
suite = @obj.class
|
|
40
|
+
instanced = @obj.instance_variables
|
|
41
|
+
consts = @obj.class.constants
|
|
42
|
+
globals = global_variables
|
|
43
|
+
classed = @obj.class.class_variables
|
|
44
|
+
obj_env = set_env(@obj, unit, instanced, consts, globals, classed)
|
|
45
|
+
myreturn =@obj.instance_variable_get("@liveunit_#{unit}".to_sym)
|
|
46
|
+
[unit, suite, obj_env, myreturn]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
##
|
|
50
|
+
#creates the reporter for each object that will be getting evaluated
|
|
51
|
+
def create_reporter(me, rep)
|
|
52
|
+
if LiveUnit.const_defined?("#{me}Reporter")
|
|
53
|
+
LiveUnit.const_get("#{me}Reporter").new
|
|
54
|
+
else
|
|
55
|
+
LiveUnit.const_set("#{me}Reporter", Class.new(rep)).new
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
##
|
|
61
|
+
#returnes the current object's state env, exluding liveunit specific variables
|
|
62
|
+
def set_env(obj, unit, instanced, consts, globals, classed)
|
|
63
|
+
my_env = {}
|
|
64
|
+
instanced.delete(:@_liveunit_evaluator)
|
|
65
|
+
instanced.delete(:@_liveunit_snapshot)
|
|
66
|
+
instanced.delete(:@_liveunit_reporter)
|
|
67
|
+
instanced.delete("@liveunit_#{unit}".to_sym)
|
|
68
|
+
instanced.each do |varname|
|
|
69
|
+
my_env.merge!({varname => obj.instance_variable_get(varname)})
|
|
70
|
+
end
|
|
71
|
+
consts.each do |con|
|
|
72
|
+
my_env.merge!({con => obj.class.const_get(con)})
|
|
73
|
+
end
|
|
74
|
+
classed.each do |varname|
|
|
75
|
+
my_env.merge!({varname => obj.class.class_variable_get(varname)})
|
|
76
|
+
end
|
|
77
|
+
my_env
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module LiveUnit
|
|
2
|
+
##
|
|
3
|
+
#loads all the required test files when the <evaluate_me> method is called
|
|
4
|
+
class Loader
|
|
5
|
+
##
|
|
6
|
+
#extracted from require_directory gem
|
|
7
|
+
def require_directory(dir, add_to_load_path = false, skip_invalid_syntax = false)
|
|
8
|
+
raise "Not a directory: #{dir}" unless File.directory?(dir)
|
|
9
|
+
if add_to_load_path
|
|
10
|
+
$LOAD_PATH << dir
|
|
11
|
+
end
|
|
12
|
+
Dir.glob(File.join(dir + '/**/*.rb')).each do |file|
|
|
13
|
+
if (skip_invalid_syntax && !(`/usr/bin/env ruby -c #{file}` =~ /Syntax OK/m))
|
|
14
|
+
warn "Invalid syntax in: #{file}"
|
|
15
|
+
next
|
|
16
|
+
end
|
|
17
|
+
require file
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require_relative "reporter.rb"
|
|
2
|
+
|
|
3
|
+
module LiveUnit
|
|
4
|
+
##
|
|
5
|
+
#default reporter that writes results to stdout
|
|
6
|
+
class PrintReporter < LiveUnit::Reporter
|
|
7
|
+
def report
|
|
8
|
+
results.each do |re|
|
|
9
|
+
puts "Failure : " + re[:case]
|
|
10
|
+
puts "Message : " + re[:msg]
|
|
11
|
+
puts re[:expectation]
|
|
12
|
+
#skip printing the env, too much noise
|
|
13
|
+
#puts "Environment : " + re[:env].to_s
|
|
14
|
+
puts
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module LiveUnit
|
|
2
|
+
##
|
|
3
|
+
#subclass this to create custom reporters
|
|
4
|
+
class Reporter
|
|
5
|
+
attr_accessor :liveunit_assertions, :liveunit_passes, :liveunit_fails, :liveunit_results
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
@liveunit_assertions = 0
|
|
9
|
+
@liveunit_passes = 0
|
|
10
|
+
@liveunit_fails = 0
|
|
11
|
+
@liveunit_results = []
|
|
12
|
+
end
|
|
13
|
+
##
|
|
14
|
+
#gets called after each evaluation to store the result
|
|
15
|
+
def report
|
|
16
|
+
#overwrite me
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
##
|
|
21
|
+
#returns the results and also clears them for the next run
|
|
22
|
+
def results
|
|
23
|
+
re = @liveunit_results
|
|
24
|
+
@liveunit_results = []
|
|
25
|
+
re
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
require "minitest/assertions"
|
|
2
|
+
|
|
3
|
+
module LiveUnit
|
|
4
|
+
##
|
|
5
|
+
#all liveunit tests will be a child of LiveUnit::TestCase
|
|
6
|
+
#uses the assertion system from Minitest
|
|
7
|
+
class TestCase
|
|
8
|
+
include Minitest::Assertions
|
|
9
|
+
attr_accessor :assertions
|
|
10
|
+
|
|
11
|
+
def initialize(obj_env, obj, myreturn)
|
|
12
|
+
@obj_env = obj_env
|
|
13
|
+
@obj = obj
|
|
14
|
+
@myreturn = myreturn
|
|
15
|
+
#for minitest
|
|
16
|
+
@assertions = 0
|
|
17
|
+
@results ||= []
|
|
18
|
+
@last_result ||={}
|
|
19
|
+
@untested = 0
|
|
20
|
+
end
|
|
21
|
+
##
|
|
22
|
+
#the unit's returned value
|
|
23
|
+
def myreturn
|
|
24
|
+
@myreturn
|
|
25
|
+
end
|
|
26
|
+
##
|
|
27
|
+
#returns a cloned version of the object where the methods are defined
|
|
28
|
+
def me
|
|
29
|
+
@obj
|
|
30
|
+
end
|
|
31
|
+
##
|
|
32
|
+
#extra msg string for tests
|
|
33
|
+
def msg(m="")
|
|
34
|
+
@m ||= m
|
|
35
|
+
end
|
|
36
|
+
##
|
|
37
|
+
#returns true if all our tests has passed
|
|
38
|
+
def passed?
|
|
39
|
+
results.each { |re| return false unless re[:passed] }
|
|
40
|
+
true
|
|
41
|
+
end
|
|
42
|
+
##
|
|
43
|
+
#expectation messages if our tests have failed
|
|
44
|
+
def result_msg
|
|
45
|
+
msgs = []
|
|
46
|
+
results.each { |re| msgs.push(re[:msg]) unless re[:passed]}
|
|
47
|
+
msgs
|
|
48
|
+
end
|
|
49
|
+
##
|
|
50
|
+
#the object's enviroment, includes constants, instance and class variables
|
|
51
|
+
def state
|
|
52
|
+
@obj_env
|
|
53
|
+
end
|
|
54
|
+
##
|
|
55
|
+
#ignore error for not implemented unit tests
|
|
56
|
+
def method_missing(m)
|
|
57
|
+
if m.to_s =~ /test_/
|
|
58
|
+
@untested += 1
|
|
59
|
+
else
|
|
60
|
+
super
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
module Minitest
|
|
68
|
+
module Assertions
|
|
69
|
+
##
|
|
70
|
+
#overwrite minitest's assert method to store our results instead of raising errors
|
|
71
|
+
def assert test, msg = nil
|
|
72
|
+
self.assertions += 1
|
|
73
|
+
unless test then
|
|
74
|
+
msg ||= "Failed assertion, no message given."
|
|
75
|
+
msg = msg.call if Proc === msg
|
|
76
|
+
end
|
|
77
|
+
@last_result = {:passed => test, :msg => msg}
|
|
78
|
+
@results.push(@last_result)
|
|
79
|
+
@last_result
|
|
80
|
+
end
|
|
81
|
+
def results
|
|
82
|
+
@results
|
|
83
|
+
end
|
|
84
|
+
def last_result
|
|
85
|
+
@last_result
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
data/liveunit.gemspec
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Gem::Specification.new do |s|
|
|
2
|
+
s.name = 'liveunit'
|
|
3
|
+
s.version = '0.0.1'
|
|
4
|
+
s.date = '2015-06-05'
|
|
5
|
+
s.required_ruby_version = '>= 2.0.0'
|
|
6
|
+
s.summary = "Example implementation to test my experiment on live unit testing. "
|
|
7
|
+
s.description = <<EOF
|
|
8
|
+
Example implementation to test my experiment on live unit testing.
|
|
9
|
+
Make sure to check the blog post here : http://zisismaras.me/general/2015/05/01/exploring-live-unit-tests.html
|
|
10
|
+
and the github repo.
|
|
11
|
+
EOF
|
|
12
|
+
|
|
13
|
+
s.files = `git ls-files`.split("\n")
|
|
14
|
+
s.add_development_dependency 'rspec', '~> 3.2', '>= 3.2.0'
|
|
15
|
+
s.add_runtime_dependency 'after_do', '~> 0.3.1'
|
|
16
|
+
s.add_runtime_dependency 'minitest', '~> 5.7', '>= 5.7.0'
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
s.authors = ["Zisis Maras"]
|
|
20
|
+
s.email = 'contact@zisismaras.me'
|
|
21
|
+
s.homepage = 'https://github.com/zisismaras/liveunit'
|
|
22
|
+
s.license = 'MIT'
|
|
23
|
+
end
|
data/spec/README.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Testing
|
|
2
|
+
Rspec has been used to test the tests(!) to avoid mix ups with the included patched minitest.
|
|
3
|
+
|
|
4
|
+
The autoloader is bad so each example should be run individually from the root directory or it will fail :
|
|
5
|
+
```
|
|
6
|
+
rspec spec/liveunit/evaluator_spec.rb
|
|
7
|
+
rspec spec/liveunit/liveunit_spec.rb
|
|
8
|
+
```
|
data/spec/fixture.rb
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require_relative "../lib/liveunit.rb"
|
|
2
|
+
class Fixture
|
|
3
|
+
include LiveUnit
|
|
4
|
+
|
|
5
|
+
def initialize
|
|
6
|
+
evaluate_me(NilReporter)
|
|
7
|
+
@myvar, @anothervar = 15, 3.14
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def calculate(num)
|
|
11
|
+
num + 10
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def hello
|
|
15
|
+
"hi"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def myarray
|
|
19
|
+
["dog", "cat", "thing"]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
require_relative "../lib/liveunit/reporter.rb"
|
|
26
|
+
class NilReporter < LiveUnit::Reporter
|
|
27
|
+
def report
|
|
28
|
+
#report nothing
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require_relative "../lib/liveunit/testcase.rb"
|
|
2
|
+
|
|
3
|
+
class TestFixture < LiveUnit::TestCase
|
|
4
|
+
|
|
5
|
+
#this fails
|
|
6
|
+
def test_calculate
|
|
7
|
+
msg "Result should be greater than 400 when @myvar=35"
|
|
8
|
+
assert_equal(35, state[:@myvar])
|
|
9
|
+
assert_operator myreturn, :>=, 400
|
|
10
|
+
end
|
|
11
|
+
#this passes
|
|
12
|
+
def test_hello
|
|
13
|
+
msg "Result should be hi"
|
|
14
|
+
assert_equal("hi", myreturn)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require_relative '../spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
RSpec.configure do |c|
|
|
4
|
+
c.order = "random"
|
|
5
|
+
c.before(:all) do
|
|
6
|
+
FileUtils.mkdir_p(File.expand_path('./livetest'))
|
|
7
|
+
FileUtils.copy(File.expand_path("./spec/livetest/test_fixture.rb"), File.expand_path("./livetest/test_fixture.rb"))
|
|
8
|
+
end
|
|
9
|
+
c.after(:all) { FileUtils.rm_r(File.expand_path('./livetest')) }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe "Evaluator" do
|
|
13
|
+
let(:fix) { Fixture.new }
|
|
14
|
+
|
|
15
|
+
describe "#evaluate" do
|
|
16
|
+
it "returnes true for passed example" do
|
|
17
|
+
fix.hello
|
|
18
|
+
snapshot = fix.evaluator.liveunit_snapshot("hello")
|
|
19
|
+
expect(fix.evaluator.evaluate(snapshot)).to eq(true)
|
|
20
|
+
end
|
|
21
|
+
it "returnes false for failed example" do
|
|
22
|
+
#call it first to get a snapshot
|
|
23
|
+
fix.calculate(40)
|
|
24
|
+
snapshot = fix.evaluator.liveunit_snapshot("calculate")
|
|
25
|
+
expect(fix.evaluator.evaluate(snapshot)).to eq(false)
|
|
26
|
+
end
|
|
27
|
+
it "returnes true for untested example" do
|
|
28
|
+
fix.myarray
|
|
29
|
+
snapshot = fix.evaluator.liveunit_snapshot("myarray")
|
|
30
|
+
expect(fix.evaluator.evaluate(snapshot)).to eq(true)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe "#liveunit_snapshot" do
|
|
35
|
+
let(:fix) { Fixture.new }
|
|
36
|
+
it "makes correct object snapshots" do
|
|
37
|
+
#call it first to get a snapshot
|
|
38
|
+
fix.hello
|
|
39
|
+
snapshot = fix.evaluator.liveunit_snapshot("hello")
|
|
40
|
+
#unit name
|
|
41
|
+
expect(snapshot[0]).to eq("hello")
|
|
42
|
+
#suite
|
|
43
|
+
expect(snapshot[1]).to eq(Fixture)
|
|
44
|
+
#env
|
|
45
|
+
expect(snapshot[2].length).to eq(8)
|
|
46
|
+
#value returned
|
|
47
|
+
expect(snapshot[3]).to eq("hi")
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
describe "#create_reporter" do
|
|
52
|
+
let(:fix) { Fixture.new }
|
|
53
|
+
it "creates reporters successfully" do
|
|
54
|
+
expect(fix.evaluator.create_reporter(Fixture, NilReporter)).to be_an_instance_of(LiveUnit::FixtureReporter)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require_relative '../spec_helper.rb'
|
|
2
|
+
|
|
3
|
+
RSpec.configure do |c|
|
|
4
|
+
c.order = "random"
|
|
5
|
+
c.before(:all) do
|
|
6
|
+
FileUtils.mkdir_p(File.expand_path('./livetest'))
|
|
7
|
+
FileUtils.copy(File.expand_path("./spec/livetest/test_fixture.rb"), File.expand_path("./livetest/test_fixture.rb"))
|
|
8
|
+
end
|
|
9
|
+
c.after(:all) { FileUtils.rm_r(File.expand_path('./livetest')) }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe "LiveUnit" do
|
|
13
|
+
let(:fix) { Fixture.new }
|
|
14
|
+
|
|
15
|
+
it "properly prepares the object" do
|
|
16
|
+
expect(fix).to respond_to(:evaluate_me, :evaluator, :reporter)
|
|
17
|
+
end
|
|
18
|
+
it "properly redefines all methods" do
|
|
19
|
+
expect(fix).to respond_to(:calculate, :hello, :myarray)
|
|
20
|
+
expect(fix).to respond_to(:liveunit_calculate, :liveunit_hello, :liveunit_myarray)
|
|
21
|
+
end
|
|
22
|
+
it "has redefined methods that work" do
|
|
23
|
+
expect(fix.hello).to eq("hi")
|
|
24
|
+
expect(fix.liveunit_hello).to eq("hi")
|
|
25
|
+
expect(fix.liveunit_hello).to eq(fix.hello)
|
|
26
|
+
end
|
|
27
|
+
it "has a reporter up and running" do
|
|
28
|
+
expect(NilReporter).to eq(LiveUnit::FixtureReporter.superclass)
|
|
29
|
+
expect(LiveUnit::Reporter).to eq(NilReporter.superclass)
|
|
30
|
+
expect(fix.reporter).to be_an_instance_of(LiveUnit::FixtureReporter)
|
|
31
|
+
end
|
|
32
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: liveunit
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Zisis Maras
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2015-06-05 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rspec
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '3.2'
|
|
20
|
+
- - ">="
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: 3.2.0
|
|
23
|
+
type: :development
|
|
24
|
+
prerelease: false
|
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
+
requirements:
|
|
27
|
+
- - "~>"
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '3.2'
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 3.2.0
|
|
33
|
+
- !ruby/object:Gem::Dependency
|
|
34
|
+
name: after_do
|
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: 0.3.1
|
|
40
|
+
type: :runtime
|
|
41
|
+
prerelease: false
|
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: 0.3.1
|
|
47
|
+
- !ruby/object:Gem::Dependency
|
|
48
|
+
name: minitest
|
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '5.7'
|
|
54
|
+
- - ">="
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: 5.7.0
|
|
57
|
+
type: :runtime
|
|
58
|
+
prerelease: false
|
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
60
|
+
requirements:
|
|
61
|
+
- - "~>"
|
|
62
|
+
- !ruby/object:Gem::Version
|
|
63
|
+
version: '5.7'
|
|
64
|
+
- - ">="
|
|
65
|
+
- !ruby/object:Gem::Version
|
|
66
|
+
version: 5.7.0
|
|
67
|
+
description: |
|
|
68
|
+
Example implementation to test my experiment on live unit testing.
|
|
69
|
+
Make sure to check the blog post here : http://zisismaras.me/general/2015/05/01/exploring-live-unit-tests.html
|
|
70
|
+
and the github repo.
|
|
71
|
+
email: contact@zisismaras.me
|
|
72
|
+
executables: []
|
|
73
|
+
extensions: []
|
|
74
|
+
extra_rdoc_files: []
|
|
75
|
+
files:
|
|
76
|
+
- ".editorconfig"
|
|
77
|
+
- Gemfile
|
|
78
|
+
- Gemfile.lock
|
|
79
|
+
- LICENSE
|
|
80
|
+
- README.md
|
|
81
|
+
- lib/liveunit.rb
|
|
82
|
+
- lib/liveunit/evaluator.rb
|
|
83
|
+
- lib/liveunit/loader.rb
|
|
84
|
+
- lib/liveunit/print_reporter.rb
|
|
85
|
+
- lib/liveunit/reporter.rb
|
|
86
|
+
- lib/liveunit/testcase.rb
|
|
87
|
+
- liveunit.gemspec
|
|
88
|
+
- spec/README.md
|
|
89
|
+
- spec/fixture.rb
|
|
90
|
+
- spec/livetest/test_fixture.rb
|
|
91
|
+
- spec/liveunit/evaluator_spec.rb
|
|
92
|
+
- spec/liveunit/liveunit_spec.rb
|
|
93
|
+
- spec/spec_helper.rb
|
|
94
|
+
homepage: https://github.com/zisismaras/liveunit
|
|
95
|
+
licenses:
|
|
96
|
+
- MIT
|
|
97
|
+
metadata: {}
|
|
98
|
+
post_install_message:
|
|
99
|
+
rdoc_options: []
|
|
100
|
+
require_paths:
|
|
101
|
+
- lib
|
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
103
|
+
requirements:
|
|
104
|
+
- - ">="
|
|
105
|
+
- !ruby/object:Gem::Version
|
|
106
|
+
version: 2.0.0
|
|
107
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
108
|
+
requirements:
|
|
109
|
+
- - ">="
|
|
110
|
+
- !ruby/object:Gem::Version
|
|
111
|
+
version: '0'
|
|
112
|
+
requirements: []
|
|
113
|
+
rubyforge_project:
|
|
114
|
+
rubygems_version: 2.4.6
|
|
115
|
+
signing_key:
|
|
116
|
+
specification_version: 4
|
|
117
|
+
summary: Example implementation to test my experiment on live unit testing.
|
|
118
|
+
test_files: []
|