clean_test 0.10.0

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.
@@ -0,0 +1,169 @@
1
+ require 'faker'
2
+
3
+ module Clean # :nodoc:
4
+ module Test # :nodoc:
5
+ # Public: Provides the ability to vend arbitrary values without using literals, or
6
+ # long calls to Faker. This has two levels of utility:
7
+ #
8
+ # helper methods - #any_number, #any_int, #any_string provide arbitrary primitives
9
+ # to make it clear what numbers, ints, and strings in your tests are
10
+ # relevant. Arbitrary values should use one of these any_ helpers.
11
+ #
12
+ # any sort of any - you can define your own "any" values by using #new_any, which allows you to
13
+ # extend things if you like. Of course, you could just make your own any_method as well.
14
+ #
15
+ # Example:
16
+ #
17
+ # class Person
18
+ # def initialize(first_name,last_name,age)
19
+ # # ...
20
+ # end
21
+ # end
22
+ #
23
+ # test_that "someone under 18 is a minor" {
24
+ # Given {
25
+ # # First name and last name aren't relevant to the test
26
+ # @person = Person.new(any_string,any_string,17)
27
+ # }
28
+ # When {
29
+ # @minor = @person.minor?
30
+ # }
31
+ # Then {
32
+ # assert @minor
33
+ # }
34
+ # }
35
+ #
36
+ # test_that "full_name gives the full name" {
37
+ # Given {
38
+ # # Age isn't relevant; it just needs to be positive
39
+ # @person = Person.new("Dave","Copeland",any_int :positive)
40
+ # }
41
+ # When {
42
+ # @full_name = @person.full_name
43
+ # }
44
+ # Then {
45
+ # assert_equal "Dave Copeland",@full_namej
46
+ # }
47
+ # }
48
+ module Any
49
+ MAX_RAND = 50000 # :nodoc:
50
+
51
+ # Public: Get any number; one that doesn't matter
52
+ #
53
+ # options - options to control what sort of number comes back:
54
+ # :positive - make sure that the number is greater than zero
55
+ # :negative - make sure that the number is less than zero
56
+ def any_number(*options)
57
+ any :number,options
58
+ end
59
+
60
+ # Public: Returns an integer. options is the same as for #any_number
61
+ def any_int(*options)
62
+ any :int,options
63
+ end
64
+
65
+ # Public: Get an arbitrary string of any potential length (the real max is 2048 characters if you don't override it)
66
+ #
67
+ # options - options to control the returned string:
68
+ # :max - the max size of the string you want
69
+ # :min - the minimum size we want to come back
70
+ #
71
+ # Example
72
+ #
73
+ # any_string :max => 255 # => ensure it'll fit into a varchar(255)
74
+ # any_string :min => 1024 # at least 1024 characters
75
+ #
76
+ def any_string(options = {})
77
+ any :string,options
78
+ end
79
+
80
+ # Public: Get a predefined, arbitrary any.
81
+ #
82
+ # sym - the any that has been defined already. By default, the following are defined:
83
+ # :string - does any_string
84
+ # String - does any_string
85
+ # :number - does any_number
86
+ # Numeric - does any_number
87
+ # Float - does any_number
88
+ # :int - does any_int
89
+ # Fixnum - does any_int
90
+ # Integer - does any_int
91
+ # options - whatever options are relevant to the user-defined any
92
+ #
93
+ # Example
94
+ #
95
+ # new_any(:foo) do |options|
96
+ # if options[:bar]
97
+ # 'bar'
98
+ # else
99
+ # 'quux'
100
+ # end
101
+ # end
102
+ #
103
+ # some_foo = any :foo
104
+ # some_other_foo = any :foo, :bar => true
105
+ def any(sym,options = {})
106
+ anies[sym].call(options)
107
+ end
108
+
109
+ # Public: Create a new any that can be retrieved via #any
110
+ #
111
+ # any - the identifer of your new any. Can be anything though a Symbol or classname would be appropriate
112
+ # block - the block that will be called whenever you #any your any.
113
+ def new_any(any,&block)
114
+ anies[any] = block
115
+ end
116
+
117
+ private
118
+
119
+ def anies
120
+ @anies ||= default_anies
121
+ end
122
+
123
+ ANY_STRING = Proc.new do |options| # :nodoc:
124
+ max_size = options[:max] || rand(2048)
125
+ min_size = options[:min] || rand(1024)
126
+ min_size = max_size if min_size > max_size
127
+
128
+ size = rand(max_size)
129
+
130
+ size = min_size if size < min_size
131
+
132
+ string = Faker::Lorem.words(1).join('')
133
+ while string.length < size
134
+ string += Faker::Lorem.words(1).join('')
135
+ end
136
+
137
+ string[0..(max_size-1)]
138
+ end
139
+
140
+ ANY_NUMBER = Proc.new do |options| # :nodoc:
141
+ number = (rand(2 * MAX_RAND) - MAX_RAND).to_f/100.0
142
+ if options.include? :positive
143
+ number + MAX_RAND
144
+ elsif options.include? :negative
145
+ number - MAX_RAND
146
+ else
147
+ number
148
+ end
149
+ end
150
+
151
+ ANY_INT = Proc.new do |options| # :nodoc:
152
+ (ANY_NUMBER.call(options)).to_i
153
+ end
154
+
155
+ def default_anies
156
+ { :string => ANY_STRING,
157
+ String => ANY_STRING,
158
+ :number => ANY_NUMBER,
159
+ Numeric => ANY_NUMBER,
160
+ Float => ANY_NUMBER,
161
+ :int => ANY_INT,
162
+ Fixnum => ANY_INT,
163
+ Integer => ANY_INT,
164
+ }
165
+ end
166
+ end
167
+ end
168
+ end
169
+
@@ -0,0 +1,186 @@
1
+ module Clean # :nodoc:
2
+ module Test # :nodoc:
3
+ # A means of documenting the parts of your test code according
4
+ # to the class "Given/When/Then" system.
5
+ # This does no enforcement of any kind and is merely documentation to make
6
+ # your tests readable.
7
+ #
8
+ # Example:
9
+ #
10
+ # Given {
11
+ # @circle = Circle.new(10)
12
+ # }
13
+ # When {
14
+ # @area = @circle.area
15
+ # }
16
+ # Then {
17
+ # assert_equal 314,@area
18
+ # }
19
+ #
20
+ # There are also two additional methods provided ,#the_test_runs and
21
+ # #mocks_shouldve_been_called to assist with creating readable tests that use mocks. See those
22
+ # methods for an example
23
+ module GivenWhenThen
24
+ # Public: Set up the conditions for the test
25
+ #
26
+ # existing_block - a callable object (e.g. a Proc) that will be called immediately
27
+ # by this Given. If nil, &block is expected to be passed
28
+ # block - a block given to this call that will be executed immediately
29
+ # by this Given. If existing_block is non-nil, this is ignored
30
+ #
31
+ # Examples
32
+ #
33
+ # Given {
34
+ # @foo = "bar"
35
+ # }
36
+ #
37
+ # Returns the block that was executed
38
+ def Given(existing_block=nil,&block)
39
+ call_block_param_or_block_given(existing_block,&block)
40
+ end
41
+ # Public: Execute the code under test
42
+ #
43
+ # existing_block - a callable object (e.g. a Proc) that will be called immediately
44
+ # by this When. If nil, &block is expected to be passed
45
+ # block - a block given to this call that will be executed immediately
46
+ # by this When. If existing_block is non-nil, this is ignored
47
+ #
48
+ # Examples
49
+ #
50
+ # When {
51
+ # @foo.go
52
+ # }
53
+ #
54
+ # Returns the block that was executed
55
+ def When(existing_block=nil,&block)
56
+ Given(existing_block,&block)
57
+ end
58
+
59
+ # Public: Verify the results of the test
60
+ #
61
+ # existing_block - a callable object (e.g. a Proc) that will be called immediately
62
+ # by this Then. If nil, &block is expected to be passed
63
+ # block - a block given to this call that will be executed immediately
64
+ # by this Then. If existing_block is non-nil, this is ignored
65
+ #
66
+ # Examples
67
+ #
68
+ # Then {
69
+ # assert_equal "bar",@foo
70
+ # }
71
+ #
72
+ # Returns the block that was executed
73
+ def Then(existing_block=nil,&block)
74
+ Given(existing_block,&block)
75
+ end
76
+
77
+ # Public: Continue the previous Given/When/Then in a new block. The reason
78
+ # you might do this is if you wanted to use the existing block form of a
79
+ # Given/When/Then, but also need to do something custom. This allows you to
80
+ # write your test more fluently.
81
+ #
82
+ # existing_block - a callable object (e.g. a Proc) that will be called immediately
83
+ # by this Then. If nil, &block is expected to be passed
84
+ # block - a block given to this call that will be executed immediately
85
+ # by this Then. If existing_block is non-nil, this is ignored
86
+ #
87
+ # Examples
88
+ #
89
+ # def circle(radius)
90
+ # lambda { @circle = Circle.new(radius) }
91
+ # end
92
+ #
93
+ # Given circle(10)
94
+ # And {
95
+ # @another_circle = Circle.new(30)
96
+ # }
97
+ #
98
+ # Returns the block that was executed
99
+ def And(existing_block=nil,&block)
100
+ Given(existing_block,&block)
101
+ end
102
+
103
+ # Public: Continue the previous Given/When/Then in a new block. The reason
104
+ # you might do this is if you wanted to use the existing block form of a
105
+ # Given/When/Then, but also need to do something custom, and that custom thing
106
+ # contradicts or overrides the flow, so an "And" wouldn't read properly. This allows you to
107
+ # write your test more fluently.
108
+ #
109
+ # existing_block - a callable object (e.g. a Proc) that will be called immediately
110
+ # by this Then. If nil, &block is expected to be passed
111
+ # block - a block given to this call that will be executed immediately
112
+ # by this Then. If existing_block is non-nil, this is ignored
113
+ #
114
+ # Examples
115
+ #
116
+ # def options
117
+ # lambda {
118
+ # @options = {
119
+ # :foo => 'bar',
120
+ # :quux => 'baz',
121
+ # }
122
+ # }
123
+ # end
124
+ #
125
+ # Given options
126
+ # But {
127
+ # @options[:foo] = 'baz'
128
+ # }
129
+ #
130
+ # Returns the block that was executed
131
+ def But(existing_block=nil,&block)
132
+ Given(existing_block,&block)
133
+ end
134
+
135
+ # Public: Used to make clear the structure of tests using mocks.
136
+ # This returns a no-op, and is intended to be used with a "When"
137
+ # to delineate the creation of a mock in a Given, and the
138
+ # expectations of a mock in a "Then"
139
+ #
140
+ # Example:
141
+ #
142
+ # Given {
143
+ # @google = mock()
144
+ # }
145
+ # When the_test_runs
146
+ # Then {
147
+ # @google.expects(:search).with('foo').returns('bar')
148
+ # }
149
+ # Given {
150
+ # @my_search = Search.new(@google)
151
+ # }
152
+ # When {
153
+ # @result = @my_search.find('foo')
154
+ # }
155
+ # Then {
156
+ # assert_equal 'Found bar',@result
157
+ # }
158
+ # And mocks_shouldve_been_called
159
+ def the_test_runs
160
+ lambda {}
161
+ end
162
+
163
+ # Public: Similar to #test_runs, this is used to make clear what
164
+ # you are testing and what the assertions are. Since many Ruby mock
165
+ # frameworks do not require an explicit "verify" step, you often have tests
166
+ # that have no explicit asserts, the assertions being simply that the mocks were called
167
+ # as expected. This step, which is a no-op, allows you to document that you are
168
+ # expecting mocks to be called. See the example in #mocks_are_called for usage.
169
+ def mocks_shouldve_been_called
170
+ lambda {}
171
+ end
172
+
173
+ private
174
+
175
+ def call_block_param_or_block_given(existing_block,&block)
176
+ if existing_block.nil?
177
+ block.call
178
+ block
179
+ else
180
+ existing_block.call
181
+ existing_block
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,32 @@
1
+ require 'test/unit'
2
+ require 'clean_test/given_when_then'
3
+ require 'clean_test/any'
4
+ require 'clean_test/test_that'
5
+
6
+ module Clean # :nodoc:
7
+ module Test # :nodoc:
8
+ # Public: A Base class brings in all modules that are part
9
+ # of Clean::Test.
10
+ #
11
+ # Example
12
+ #
13
+ # class TestCircle < Clean::Test::TestCase
14
+ # test_that {
15
+ # Given { @circle = Circle.new(10) }
16
+ # When { @area = @circle.area }
17
+ # Then { assert_equal 314,@area }
18
+ # }
19
+ # end
20
+ class TestCase < ::Test::Unit::TestCase
21
+ include GivenWhenThen
22
+ include TestThat
23
+ include Any
24
+ if RUBY_VERSION =~ /^1\.8\./
25
+ # Avoid the stupid behavior of
26
+ # complaining that no tests were specified for 1.8.-like rubies
27
+ def default_test
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,65 @@
1
+ module Clean # :nodoc:
2
+ module Test # :nodoc:
3
+ # Public: Module that, when included, makes a class method, +#test_that+ available
4
+ # to create test methods in a more fluent way. See ClassMethods.
5
+ module TestThat
6
+ def self.included(base)
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+
12
+ # Public: Create a new test method with the given optional description and
13
+ # body.
14
+ #
15
+ # description - a string describing what is being tested; write this as a follow on
16
+ # from the phrase "test that". If nil, a name will be constructed
17
+ # based on the block
18
+ # block - the body of the test.
19
+ #
20
+ # Example
21
+ #
22
+ # # Create a rails-style test method
23
+ # test_that "area is computed based on positive radius" do
24
+ # Given {
25
+ # @circle = Circle.new(10)
26
+ # }
27
+ # When {
28
+ # @area = @circle.area
29
+ # }
30
+ # Then {
31
+ # assert_equal 314,@area
32
+ # }
33
+ # end
34
+ #
35
+ # # Create an "anonymous" test, where the test body
36
+ # # is clear enough as to what's being tested
37
+ # test_that {
38
+ # Given a_circle(:radius => 10)
39
+ # When get_area
40
+ # Then area_should_be(314)
41
+ # }
42
+ def test_that(description=nil,&block)
43
+ raise "You must provide a block" if block.nil?
44
+ description = make_up_name(block) if description.nil?
45
+ test_name = "test_#{description.gsub(/\s+/,'_')}".to_sym
46
+ defined = instance_method(test_name) rescue false
47
+ raise "#{test_name} is already defined in #{self}" if defined
48
+ define_method(test_name, &block)
49
+ end
50
+
51
+ private
52
+
53
+ def make_up_name(some_proc)
54
+ if some_proc.respond_to? :source_location
55
+ name,location = some_proc.source_location
56
+ "anonymous test at #{name}, line #{location}"
57
+ else
58
+ "anonymous test for proc #{some_proc.object_id}"
59
+ end
60
+ end
61
+ end
62
+
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,5 @@
1
+ module Clean # :nodoc:
2
+ module Test # :nodoc:
3
+ VERSION = "0.10.0"
4
+ end
5
+ end
data/test/bootstrap.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_filter "/test/*.rb"
4
+ end
5
+
data/test/test_any.rb ADDED
@@ -0,0 +1,144 @@
1
+ require 'test/unit'
2
+ require 'clean_test/test_case'
3
+
4
+ class TestAny < Clean::Test::TestCase
5
+ test_that {
6
+ Given { random_seeded_for_negative_float }
7
+ When { @number = any_number }
8
+ Then {
9
+ assert @number < 0,"any_number should be negative, but we got #{@number}"
10
+ assert @number.to_i != @number,"Expected a float"
11
+ }
12
+ }
13
+ test_that {
14
+ Given { random_seeded_for_positive }
15
+ When { @number = any_number }
16
+ Then { assert @number > 0,"any_number should be positive, but we got #{@number}" }
17
+ }
18
+
19
+ test_that {
20
+ Given { random_seeded_for_negative_float }
21
+ When { @number = any_number :positive }
22
+ Then { assert @number > 0,"We specified :positive, but got a negative" }
23
+ }
24
+
25
+ test_that {
26
+ Given { random_seeded_for_positive }
27
+ When { @number = any_number :negative }
28
+ Then { assert @number < 0,"We specified :negative, but got a positive" }
29
+ }
30
+
31
+ test_that {
32
+ Given { random_seeded_for_negative_float }
33
+ When { @number = any_int }
34
+ Then {
35
+ assert @number < 0,"Expected int to be negative"
36
+ assert_equal @number.to_i,@number,"Expected an int, not a #{@number.class}"
37
+ }
38
+ }
39
+
40
+ test_that {
41
+ Given { random_seeded_for_negative_float }
42
+ When { @int = any_int :positive }
43
+ Then { assert @int > 0,"We specified :positive, but got a negative" }
44
+ }
45
+
46
+ test_that {
47
+ Given { random_seeded_for_positive }
48
+ When { @int = any_int :negative }
49
+ Then { assert @int < 0,"We specified :negative, but got a positive" }
50
+ }
51
+
52
+ test_that {
53
+ Given { random_seeded_for_long_string }
54
+ When { @string = any_string }
55
+ Then {
56
+ assert @string.length < 1441,"expected less than our rand value, but got #{@string.length}"
57
+ assert_equal String,@string.class
58
+ }
59
+ }
60
+
61
+ test_that {
62
+ Given { random_seeded_for_long_string }
63
+ When { @string = any_string :max => 255 }
64
+ Then {
65
+ assert @string.length <= 255,"Expected a string of less than 256 characters, got #{@string.length}"
66
+ assert_equal String,@string.class
67
+ }
68
+ }
69
+
70
+ test_that {
71
+ Given { random_seeded_for_long_string }
72
+ When { @string = any_string :min => 1000 }
73
+ Then {
74
+ assert @string.length > 1000,"Expected a string of at least 1500 characters, got one of #{@string.length} characters"
75
+ assert_equal String,@string.class
76
+ }
77
+ }
78
+
79
+ test_that "we can register custom anys" do
80
+ Given {
81
+ new_any :foo do
82
+ "bar"
83
+ end
84
+ }
85
+ When {
86
+ @result = any :foo
87
+ }
88
+ Then {
89
+ assert_equal 'bar',@result
90
+ }
91
+ end
92
+
93
+ test_that "custom anys can take options" do
94
+ Given {
95
+ new_any :foo do |options|
96
+ if options[:baaz]
97
+ 'quux'
98
+ else
99
+ 'bar'
100
+ end
101
+ end
102
+ }
103
+ When {
104
+ @result = any :foo, :baaz => true
105
+ }
106
+ Then {
107
+ assert_equal 'quux',@result
108
+ }
109
+ end
110
+
111
+ [String,[Integer,Fixnum],Fixnum,Float,[Numeric,Float]].each do |klass|
112
+ test_that "can get an any #{klass}" do
113
+ Given {
114
+ @class = @expected_class = klass
115
+ if @class.kind_of? Array
116
+ @expected_class = @class[1]
117
+ @class = @class[0]
118
+ end
119
+ }
120
+ When {
121
+ @value = any @class
122
+ }
123
+ Then {
124
+ assert_not_nil @value
125
+ assert_equal @expected_class,@value.class
126
+ }
127
+ end
128
+ end
129
+
130
+ private
131
+
132
+ def random_seeded_for_long_string
133
+ Random.srand(34)
134
+ end
135
+
136
+ def random_seeded_for_negative_float
137
+ Random.srand(45)
138
+ end
139
+
140
+ def random_seeded_for_positive
141
+ Random.srand(2)
142
+ end
143
+
144
+ end
@@ -0,0 +1,17 @@
1
+ require 'clean_test/test_case'
2
+
3
+ class Circle
4
+ def initialize(radius)
5
+ @radius = radius
6
+ end
7
+
8
+ def area; (3.14 * @radius * @radius).to_i; end
9
+ end
10
+
11
+ class TestCircle < Clean::Test::TestCase
12
+ test_that {
13
+ Given { @circle = Circle.new(10) }
14
+ When { @area = @circle.area }
15
+ Then { assert_equal 314,@area }
16
+ }
17
+ end