testify 0.0.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ -c
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'classy'
4
+
5
+ group :development do
6
+ gem 'jeweler'
7
+ end
8
+
9
+ group :test do
10
+ gem 'rspec'
11
+ end
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009 John Hyland and Emily Price
1
+ Copyright (c) 2010 John Hyland
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -2,6 +2,105 @@
2
2
 
3
3
  Testify is a test framework framework. Think "Rack for testing."
4
4
 
5
+ == Overview
6
+
7
+ Like Rack, Testify is typically going to be run as a stack of applications that
8
+ implement a +call+ method. In typical usage, the stack will be assembled by a
9
+ Runner and consist of a Framework and optionally some middleware, but this
10
+ isn't a requirement.
11
+
12
+ The source and detailed documentation can be found at
13
+ http://github.com/djspinmonkey/testify and
14
+ http://rdoc.info/projects/djspinmonkey/testify, respectively.
15
+
16
+ == Testify Applications
17
+
18
+ A Testify Application is any object that implements a +call+ method accepting a
19
+ single argument. The one argument will be a hash (canonically called env), and
20
+ the return value should be an array of TestResult objects.
21
+
22
+ === The +env+ Hash
23
+
24
+ The +env+ hash should be an instance of Hash with one of the following keys
25
+ defined:
26
+
27
+ [:files] an array of filenames containing the tests
28
+ [:path] a path containing the files containing the tests
29
+
30
+ In addition, all of the following keys should be defined:
31
+
32
+ [:testify_version] An array of integers representing this version of Testify
33
+ [:hooks] A hash of callbacks - see below.
34
+
35
+ Given that Testify is still at a fairly early stage of development, it is quite
36
+ possible that more required keys will be added later.
37
+
38
+ === Middleware
39
+
40
+ Middleware will generally either modify the env hash before the framework gets
41
+ it (eg, to execute only a subset of tests), or modify the TestResult objects on
42
+ the way back out (eg, to colorize the result text). If you want to respond to
43
+ a particular event as it happens (eg, send a Growl notification when a test
44
+ fails), it is probably best to do this by adding a hook rather than looking at
45
+ the returned TestResult objects, since call() will not return until all the
46
+ tests have finished running.
47
+
48
+ === Frameworks
49
+
50
+ A Framework object is responsible for actually running the tests and generating
51
+ TestResult objects. Frameworks are required to respect all of the hooks
52
+ described below. Generally, Frameworks should inherit from
53
+ Testify::Framework::Base and should have at least one alias in order to benefit
54
+ from all of Testify's built-in functionality, but neither of these is a
55
+ requirement. (See the Aliasable module in the Classy gem for a more thorough
56
+ description of aliases. http://github.com/djspinmonkey/classy)
57
+
58
+ At least initially, most Framework classes will likely be adaptors for existing
59
+ test frameworks (RSpec, Test::Unit, etc).
60
+
61
+ === Hooks
62
+
63
+ env[:hooks] is a hash containing arrays of callable objects (usually Procs,
64
+ but anything responding to +call+ will work) which will be called in specific
65
+ circumstances. The following keys should supported:
66
+
67
+ [:before_all] Will be called before running any tests. An array of Test
68
+ objects will be passed in. A middleware app might use this hook
69
+ instead of simply running immediately if it needed access to
70
+ individual tests instead of just files, or if it needed to run
71
+ after all other middleware. For example, if some other
72
+ middleware later in the stack were excluding some subset of tests
73
+ from running, you might need to be sure you were operating only
74
+ on the tests that would actually be run.
75
+ [:after_all] Will be called after running all tests. An array of TestResult
76
+ objects will be passed in. Middleware setting this hook should
77
+ probably just work with the array of TestResults returned from
78
+ calling the next Testify app on the stack instead, unless it
79
+ needs to run before the results pass through any other
80
+ middleware. Note that there is no guarantee another hook may not
81
+ be added prior to yours, however.
82
+ [:before_each] Will be called before running each individual test. A single
83
+ Test object will be passed in.
84
+ [:after_each] Will be called after running each individual test. A single
85
+ TestResult object will be passed in.
86
+ [:after_status] Points to a hash containing symbols as the keys, and arrays of
87
+ callable objects to be called whenever a TestResult is generated
88
+ with the status corresponding to that symbol. The TestResult
89
+ will be passed in.
90
+
91
+ If using the values provided by +Testify.env_defaults+, values for the first
92
+ four keys will be initialized to empty arrays, and +:after_status+ will be
93
+ initialized to an empty hash.
94
+
95
+ Like the +env+ hash, this is highly subject to change at this point.
96
+
97
+ == TODO
98
+
99
+ * Write adaptors for common test frameworks (rspec and minitest first, probably).
100
+ * Write an autotest-like Runner
101
+ * Write some useful middleware (growl notifications, colorized output, etc)
102
+ * World domination!
103
+
5
104
  == Note on Patches/Pull Requests
6
105
 
7
106
  * Fork the project.
@@ -15,4 +114,4 @@ Testify is a test framework framework. Think "Rack for testing."
15
114
 
16
115
  == Copyright
17
116
 
18
- Copyright (c) 2009 John Hyland and Emily Price. See LICENSE for details.
117
+ Copyright (c) 2010 John Hyland. See LICENSE for details.
data/Rakefile CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'rake'
3
+ require 'rspec/core/rake_task'
3
4
 
4
5
  begin
5
6
  require 'jeweler'
@@ -9,7 +10,8 @@ begin
9
10
  #gem.description = %Q{TODO: longer description of your gem}
10
11
  gem.email = "github@djspinmonkey.com"
11
12
  gem.homepage = "http://github.com/djspinmonkey/testify"
12
- gem.authors = ["John Hyland", "Emily Price"]
13
+ gem.authors = ["John Hyland"]
14
+ gem.add_dependency "classy", ">= 1.0.0"
13
15
  gem.add_development_dependency "rspec", ">= 1.2.9"
14
16
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
17
  end
@@ -18,28 +20,27 @@ rescue LoadError
18
20
  puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
19
21
  end
20
22
 
21
- require 'spec/rake/spectask'
22
- Spec::Rake::SpecTask.new(:spec) do |spec|
23
- spec.libs << 'lib' << 'spec'
24
- spec.spec_files = FileList['spec/**/*_spec.rb']
23
+ RSpec::Core::RakeTask.new do |t|
25
24
  end
26
25
 
27
- Spec::Rake::SpecTask.new(:rcov) do |spec|
28
- spec.libs << 'lib' << 'spec'
29
- spec.pattern = 'spec/**/*_spec.rb'
30
- spec.rcov = true
26
+ RSpec::Core::RakeTask.new(:coverage) do |t|
27
+ t.rcov = true
28
+ t.rcov_opts = ['--exclude', 'spec']
31
29
  end
32
30
 
33
- task :spec => :check_dependencies
31
+ task :spec
34
32
 
35
33
  task :default => :spec
36
34
 
37
- require 'rake/rdoctask'
38
- Rake::RDocTask.new do |rdoc|
39
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
40
-
41
- rdoc.rdoc_dir = 'rdoc'
42
- rdoc.title = "testify #{version}"
43
- rdoc.rdoc_files.include('README*')
44
- rdoc.rdoc_files.include('lib/**/*.rb')
45
- end
35
+ # This is generating some annoying warnings - commented out for now until I
36
+ # figure out how to quiet it down.
37
+ #
38
+ #require 'rdoc/task'
39
+ #RDoc::Task.new do |rdoc|
40
+ # version = File.exist?('VERSION') ? File.read('VERSION') : ""
41
+ #
42
+ # rdoc.rdoc_dir = 'rdoc'
43
+ # rdoc.title = "testify #{version}"
44
+ # rdoc.rdoc_files.include('README*')
45
+ # rdoc.rdoc_files.include('lib/**/*.rb')
46
+ #end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,115 @@
1
+ module Testify
2
+ # The module which all Framework classes are recommended to inherit.
3
+ # Framework provides a few utility methods and a means to keep track of all
4
+ # Framework classes (via Aliasable). Framework objects are Testify apps, so
5
+ # subclasses must implement a +call+ method as described in the README.rdoc
6
+ # file. It is also good practice to declare at least one alias (see the
7
+ # Aliasable module in the Classy gem for more details).
8
+ #
9
+ module Framework
10
+ include Aliasable
11
+
12
+ # The default set of statuses
13
+ #
14
+ DEFAULT_STATUSES = [ :passed, :pending, :failed, :error ]
15
+
16
+ # Extend the ClassMethods module and set the default statuses.
17
+ #
18
+ # :nodoc:
19
+ #
20
+ def self.included( klass )
21
+ klass.extend Testify::Framework::ClassMethods
22
+ klass.statuses *Testify::Framework::DEFAULT_STATUSES.dup
23
+ super
24
+ end
25
+
26
+ # Returns an array of absolute paths to each file defined by an +env+
27
+ # hash. The default implementation either returns the array of files, if
28
+ # :files is defined in the hash, or returns every file found in a
29
+ # traversal of the path in the :path key. Raises an exception if neither
30
+ # is defined, since that is not a valid +env+ hash.
31
+ #
32
+ # If a particular framework should only process files with names matching
33
+ # a particular glob pattern (eg, RSpec only wants files that match
34
+ # `*_spec.rb`), it can specify this with +file_pattern+.
35
+ #
36
+ def files( env )
37
+ return env[:files] if env.include? :files
38
+ raise(ArgumentError, "env hash must include either :files or :path") unless env.include? :path
39
+
40
+ file_glob = self.class.class_eval { @file_pattern } || '*'
41
+ Dir.glob(File.join(env[:path], '**', file_glob))
42
+ end
43
+
44
+ # Run all the appropriate hooks before running any tests at all.
45
+ #
46
+ def run_before_all_hooks( env )
47
+ env[:hooks][:before_all].each { |hook| hook.call }
48
+ end
49
+
50
+ # Run all the appropriate hooks before running each test.
51
+ #
52
+ def run_before_each_hooks( env )
53
+ env[:hooks][:before_each].each { |hook| hook.call }
54
+ end
55
+
56
+ # Run all the appropriate hooks after running all the tests
57
+ #
58
+ def run_after_all_hooks( env, results )
59
+ env[:hooks][:after_all].each { |hook| hook.call(results) }
60
+ end
61
+
62
+ # Run all the appropriate hooks after running each test individually
63
+ # (including the hooks for a particular status).
64
+ #
65
+ def run_after_each_hooks( env, result )
66
+ hooks = env[:hooks][:after_each]
67
+ hooks += env[:hooks][:after_status][result.status].to_a # .to_a in case it's nil
68
+ hooks.each { |hook| hook.call(result) }
69
+ end
70
+
71
+ module ClassMethods
72
+ # Gets and sets an array of symbols corresponding to the possible
73
+ # TestResult statuses that might be set by this Framework.
74
+ #
75
+ # For example, a framework with tests that can only pass or fail might
76
+ # like like this:
77
+ #
78
+ # class SomeFramework
79
+ # include Testify::Framework
80
+ #
81
+ # statuses :passed, :failed
82
+ #
83
+ # ...
84
+ # end
85
+ #
86
+ # SomeFramework.statuses # => [ :passed, :failed ]
87
+ #
88
+ def statuses( *new_statuses )
89
+ if new_statuses.any?
90
+ @statuses = new_statuses
91
+ end
92
+ @statuses
93
+ end
94
+
95
+ # Accepts a glob pattern that limits the paths returned by `#files`.
96
+ # Only paths with filenames that match this pattern will be returned by
97
+ # +.files+.
98
+ #
99
+ # For example, if all your framework's test files should end in
100
+ # _mytests.rb, you might do this:
101
+ #
102
+ # class MyTestFramework
103
+ # include Testify::Framework
104
+ #
105
+ # file_pattern '*_mytests.rb'
106
+ #
107
+ # ...
108
+ # end
109
+ #
110
+ def file_pattern( pattern )
111
+ self.class_eval { @file_pattern = pattern }
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,20 @@
1
+ module Testify
2
+ module Middleware
3
+ include Aliasable
4
+
5
+ # By default, Testify middleware is initialized with only the next app on
6
+ # the stack. If you override this, you may also need to override
7
+ # Runner.construct_app_stack.
8
+ #
9
+ def initialize(app)
10
+ @app = app
11
+ end
12
+
13
+ # By default, the middleware base class just calls the next app on the
14
+ # stack - you will almost certainly want to override this method.
15
+ #
16
+ def call(env)
17
+ @app.call(env)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,138 @@
1
+ module Testify
2
+
3
+ # Runner is a Testify app intended to sit at the top of a Testify stack and
4
+ # provide a simple mechanism for running a set of tests. If you're writing
5
+ # an autotest-like application, Runner is what you would use. Runner uses
6
+ # Templatable from the Classy gem, so you can either subclass Runner and use
7
+ # DSL-like class methods to define its behavior, or instantiate it directly
8
+ # and configure the instance.
9
+ #
10
+ # For example,
11
+ #
12
+ # class SampleRunner
13
+ # include Testify::Runner
14
+ #
15
+ # framework :rspec
16
+ # middleware :growl, :red_green
17
+ # end
18
+ #
19
+ # @runner = SampleRunner.new
20
+ #
21
+ # would be equivalent to
22
+ #
23
+ # @runner = Testify::Runner::Base.new
24
+ # @runner.framework = Testify::Framework::RspecAdaptor
25
+ # @runner.middleware = [Testify::Middleware::Growl, Testify::Middleware::RedGreen]
26
+ #
27
+ # Which approach is best depends on your needs, or you can use a mixture of
28
+ # the two.
29
+ #
30
+ module Runner
31
+ def self.included( klass )
32
+ klass.class_eval do
33
+ extend Templatable
34
+ extend Testify::Runner::ClassMethods
35
+
36
+ attr_accessor :status, :framework_instance, :test_results
37
+ templatable_attr :framework, :middleware
38
+
39
+ @@middleware = []
40
+ end
41
+ super
42
+ end
43
+
44
+ # Allows the framework to be specified on an instance of Runner. See +.framework+.
45
+ #
46
+ def framework= (fw)
47
+ @framework = Testify::Framework::Base.find(fw)
48
+ end
49
+
50
+ # Allows the middleware array to be specified for an instance of Runner. See +.middleware+.
51
+ #
52
+ # Note: The class method accepts a list, but the instance method must be passed an actual array.
53
+ #
54
+ # Example:
55
+ #
56
+ # runner = YourRunner.new
57
+ # runner.middleware = [:dots, :colorize]
58
+ #
59
+ def middleware=( middleware )
60
+ @middleware = middleware.map { |mw| Testify::Middleware.find(mw) }
61
+ end
62
+
63
+ # Constructs the stack of middleware and framework. If you are doing
64
+ # something unconventional (eg, creating middleware that requires
65
+ # additional initialization parameters), you may need to override this
66
+ # method.
67
+ #
68
+ def construct_app_stack
69
+ @framework_instance ||= framework.new
70
+ top_app = @framework_instance
71
+
72
+ middleware.each do |mw_class|
73
+ top_app = mw_class.new(top_app)
74
+ end
75
+
76
+ top_app
77
+ end
78
+
79
+ # Run the tests. Accepts a hash that will be merged in to the default env
80
+ # and passed to the Testify app stack.
81
+ #
82
+ def run( options = {} )
83
+ top_app = construct_app_stack
84
+
85
+ env = Testify.env_defaults.merge options
86
+ @test_results = top_app.call(env)
87
+
88
+ @status = @test_results.collect(&:status).max # XXX: Optimize?
89
+
90
+ @test_results
91
+ end
92
+
93
+ module ClassMethods
94
+ # Defines and/or returns the framework to use. This can be any class whose
95
+ # instances are Testify apps, and an instance of this class will be placed
96
+ # at the bottom of the Testify stack used by Runner#run. Typically, this
97
+ # will probably be a test framework built on Testify or (more likely, at
98
+ # least for now) a Testify adaptor for some existing framework. If the
99
+ # class descends from Testify::Framework::Base and defines an alias (eg,
100
+ # aka :rspec), you may use that alias instead of passing in the actual
101
+ # class.
102
+ #
103
+ # Example:
104
+ #
105
+ # class YourRunner < Testify::Runner::Base
106
+ # framework :rspec
107
+ # end
108
+ # @runner = YourRunner.new
109
+ # @runner.framework # <= Testify::Framework::RspecAdaptor
110
+ #
111
+ # Note that you can also specify the framework on an instance, using
112
+ # +#framework=+.
113
+ #
114
+ # @runner = Testify::Runner.new
115
+ # @runner.framework YourAwesomeTestifyFrameworkClass
116
+ #
117
+ def framework( fw = nil )
118
+ self.framework = Testify::Framework.find(fw) if fw
119
+ self.send(:class_variable_get, :@@framework)
120
+ end
121
+
122
+ # Defines and/or returns the middleware to use, in the same manner as
123
+ # +.framework+. Note that this completely replaces any previous
124
+ # middleware specified for this class.
125
+ #
126
+ # Example:
127
+ #
128
+ # class YourRunner < Testify::Runner::Base
129
+ # middleware :dots, :colorize
130
+ # end
131
+ #
132
+ def middleware( *middlewares )
133
+ self.middleware = middlewares.map { |mw| Testify::Middleware.find(mw) } unless middlewares.empty?
134
+ self.send(:class_variable_get, :@@middleware)
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,18 @@
1
+ module Testify
2
+
3
+ # A TestResult object represents the results of running a single test,
4
+ # whatever that means in the context of your framework.
5
+ #
6
+ class TestResult
7
+ attr_accessor :status, :message, :file, :line
8
+
9
+ def initialize (options = {})
10
+ @status = options[:status]
11
+ @message = options[:message]
12
+ @file = options[:file]
13
+ @line = options[:line]
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,41 @@
1
+ # gems
2
+ require 'classy'
3
+
4
+ # Make sure we're grabbing the right version of everything.
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
6
+
7
+ require 'framework'
8
+ require 'runner'
9
+ require 'middleware'
10
+ require 'test_result'
11
+
12
+ # Put the LOAD_PATH back the way it was.
13
+ $LOAD_PATH.shift
14
+
15
+ # The Testify module provides some general-purpose functions that aren't
16
+ # specific to any single component.
17
+ module Testify
18
+
19
+ # Provides some reasonable defaults to create a new env hash. This method
20
+ # does not fill in :path or :files, so you'll need to explicitly specify one
21
+ # or the other.
22
+ #
23
+ def self.env_defaults
24
+ { :testify_version => Testify.version,
25
+ :hooks => { :before_all => [],
26
+ :after_all => [],
27
+ :before_each => [],
28
+ :after_each => [],
29
+ :after_status => {},
30
+ }
31
+ }
32
+ end
33
+
34
+ # Returns the current version as an array. (Eg, version 1.2.3 would be
35
+ # returned as [1, 2, 3].)
36
+ #
37
+ def self.version
38
+ File.read(File.join(File.dirname(__FILE__), '..', 'VERSION')).chomp.split('.').collect { |n| n.to_i }
39
+ end
40
+
41
+ end
@@ -0,0 +1,9 @@
1
+ This is a sample Testify-based setup. The framework is called (imaginatively
2
+ enough) AwesomeTestFramework - this is the same level as RSpec or minitest.
3
+ The runner is called AwesomeRunner - think of the 'rspec' command or
4
+ 'autotest'. And for flavor we've added some middleware to output valuable
5
+ information while the tests run and append some footer text at the end.
6
+
7
+ To see it in action, just run this:
8
+
9
+ ./awesome_runner.rb awesome_tests
@@ -0,0 +1,28 @@
1
+ require_relative '../lib/testify'
2
+ require_relative 'awesome_test_framework'
3
+ require_relative 'dots'
4
+ require_relative 'summary'
5
+
6
+ class AwesomeRunner
7
+ include Testify::Runner
8
+
9
+ # Specify the framework we want to use. This alias is defined in
10
+ # AwesomeTestFramework.
11
+ #
12
+ framework :awesome
13
+
14
+ # Specify the middleware. Again, this is defined in RadMiddleware.
15
+ #
16
+ middleware :summary, :dots
17
+ end
18
+
19
+ # Instantiate the runner and run the tests.
20
+ #
21
+ tests_path = File.join(File.dirname(__FILE__), 'awesome_tests')
22
+ @runner = AwesomeRunner.new
23
+ results = @runner.run(:path => tests_path)
24
+
25
+ #puts "#{results.size} tests run"
26
+ #results.each do |res|
27
+ # puts "#{res.status} - #{res.message}"
28
+ #end
@@ -0,0 +1,51 @@
1
+ # A sample test framework built using Testify.
2
+ #
3
+ class AwesomeTestFramework
4
+ include Testify::Framework
5
+
6
+ # Specify an alias for this framework.
7
+ #
8
+ aka :awesome
9
+
10
+ # These are the statuses this framework might return, in increasing order of severity.
11
+ #
12
+ statuses :pass, :fail, :error
13
+
14
+ # This is what a test file for this framework looks like.
15
+ #
16
+ file_pattern '*.aws'
17
+
18
+ # This is where you do your thing. In a real test framework, you'd probably
19
+ # be testing assertions and setting up contexts and generally making the
20
+ # magic happen here (or at least calling the libraries where the magic
21
+ # happens).
22
+ #
23
+ # In this example, we're just reading test results out of a file and calling
24
+ # the appropriate hooks.
25
+ #
26
+ def call( env )
27
+ results = []
28
+
29
+ run_before_all_hooks(env)
30
+
31
+ files(env).each do |file|
32
+ open file do |f|
33
+ f.lines.each_with_index do |line, line_number|
34
+ run_before_each_hooks(env)
35
+
36
+ message, status = * line.split(':')
37
+ status = status.strip.to_sym
38
+ result = Testify::TestResult.new( :file => file, :line => line_number, :message => message, :status => status )
39
+ results << result
40
+
41
+ run_after_each_hooks(env, result)
42
+ end
43
+ end
44
+ end
45
+
46
+ run_after_all_hooks(env, results)
47
+
48
+ results
49
+ end
50
+
51
+ end
@@ -0,0 +1,3 @@
1
+ five should be an integer: pass
2
+ love should be in the air: pass
3
+ garble barf: asplode
@@ -0,0 +1,3 @@
1
+ axioms should not be testable: pass
2
+ goods should be fungible: pass
3
+ this framework should be awesome: fail
@@ -0,0 +1,3 @@
1
+ true should be true: pass
2
+ 1 + 1 should equal 2: pass
3
+ this test should pass: pass
@@ -0,0 +1,31 @@
1
+ # Output a dot every time a test passes, an F when it fails, or a E on an
2
+ # error. On any other status, it prints a ?.
3
+ #
4
+ class Dots
5
+ include Testify::Middleware
6
+
7
+ aka :dots
8
+
9
+ def call( env )
10
+ # Output dots (et al) as each test runs.
11
+ #
12
+ env[:hooks][:after_each].push(lambda do |result|
13
+ case result.status
14
+ when :pass
15
+ print '.'
16
+ when :fail
17
+ print 'F'
18
+ when :error
19
+ print 'E'
20
+ else
21
+ print '?'
22
+ end
23
+ end)
24
+
25
+ # Output a couple newlines at the end after all the tests have run.
26
+ #
27
+ env[:hooks][:after_all].push(lambda { |ignored| puts; puts })
28
+
29
+ @app.call(env)
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ # Output a summary of the test results after they've all been run.
2
+ #
3
+ class Summary
4
+ include Testify::Middleware
5
+
6
+ aka :summary
7
+
8
+ def call( env )
9
+ results = @app.call(env)
10
+
11
+ summary = Hash.new(0)
12
+ results.each { |res| summary[res.status] += 1 }
13
+
14
+ puts "Ran #{results.size} tests in all"
15
+ summary.each { |status, count| puts "#{count} tests with status #{status}" }
16
+
17
+ results
18
+ end
19
+ end
@@ -0,0 +1,81 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe "Testify::Framework" do
4
+
5
+ before :all do
6
+ Testify::Framework.forget_aliases
7
+
8
+ destroy_class :VanillaFramework
9
+ class VanillaFramework
10
+ include Testify::Framework
11
+ aka :vanilla
12
+ end
13
+ @framework = VanillaFramework.new
14
+ end
15
+
16
+ it "should be able to specify known aliases" do
17
+ Testify::Framework.find(:vanilla).should equal VanillaFramework
18
+ end
19
+
20
+ it "should raise an ArgumentError if a given alias is already taken" do
21
+ lambda {
22
+ class ThisIsTheRepeat
23
+ include Testify::Framework
24
+ aka :vanilla
25
+ end
26
+ }.should raise_error(ArgumentError)
27
+
28
+ end
29
+
30
+ it "should be able to specify a status ranking without affecting other Frameworks" do
31
+ class ChangedFramework
32
+ include Testify::Framework
33
+ statuses :passed, :failed, :exploded
34
+ end
35
+
36
+ VanillaFramework.statuses.should eql Testify::Framework::DEFAULT_STATUSES
37
+ ChangedFramework.statuses.should eql [ :passed, :failed, :exploded ]
38
+ end
39
+
40
+ context '#files' do
41
+ before do
42
+ @test_path = File.join(File.dirname(__FILE__), "sample_tests")
43
+ all_files = ['failing_tests', 'mixed_tests', 'passing_tests', 'test_helper']
44
+ test_files = all_files - ['test_helper']
45
+ @all_paths = all_files.collect { |f| File.join(File.dirname(__FILE__), 'sample_tests', f) }
46
+ @test_paths = test_files.collect { |f| File.join(File.dirname(__FILE__), 'sample_tests', f) }
47
+ end
48
+
49
+ after do
50
+ VanillaFramework.file_pattern nil
51
+ end
52
+
53
+ it "should find files specified by :path" do
54
+ env = { :path => @test_path }
55
+ @framework.files(env).sort.should eql @all_paths
56
+ end
57
+
58
+ it "should find files specified by :files" do
59
+ env = { :files => @all_paths }
60
+ @framework.files(env).sort.should eql @all_paths
61
+ end
62
+
63
+ it "should raise an ArgumentError if neither :files nor :path is defined" do
64
+ env = {}
65
+ lambda {
66
+ @framework.files(env)
67
+ }.should raise_exception ArgumentError
68
+ end
69
+
70
+ it "should respect the .file_pattern setting" do
71
+ class VanillaFramework
72
+ file_pattern '*_tests'
73
+ end
74
+
75
+ env = { :path => @test_path }
76
+ @framework.files(env).sort.should eql @test_paths
77
+ end
78
+ end
79
+
80
+ end
81
+
@@ -0,0 +1,5 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe "Testify::Middleware::Base" do
4
+ # It doesn't actually do anything that doesn't come from a module.
5
+ end
@@ -0,0 +1,101 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe "Testify::Runner" do
4
+
5
+ before :each do
6
+ Testify::Middleware.forget_aliases
7
+ Testify::Framework.forget_aliases
8
+
9
+ destroy_class :SomeMiddleware
10
+ class SomeMiddleware
11
+ include Testify::Middleware
12
+ aka :some_middleware
13
+ end
14
+
15
+ destroy_class :SomeMoreMiddleware
16
+ class SomeMoreMiddleware
17
+ include Testify::Middleware
18
+ aka :more_middleware
19
+ end
20
+
21
+ destroy_class :SomeTestFramework
22
+ class SomeTestFramework
23
+ include Testify::Framework
24
+
25
+ aka :some_test_framework
26
+ attr_accessor :env
27
+
28
+ def call (env)
29
+ @env = env
30
+ [Testify::TestResult.new(:message => "Testing", :status => :pass)]
31
+ end
32
+ end
33
+
34
+ destroy_class :TestRunner
35
+ class TestRunner
36
+ include Testify::Runner
37
+ end
38
+ @runner = TestRunner.new
39
+
40
+ @test_path = File.expand_path(File.join(File.dirname(__FILE__), 'sample_tests'))
41
+ end
42
+
43
+ it "should be able to specify a test framework by alias" do
44
+ class TestRunner
45
+ framework :some_test_framework
46
+ end
47
+
48
+ TestRunner.framework.should eql SomeTestFramework
49
+ @runner.framework.should eql SomeTestFramework
50
+ end
51
+
52
+ it "should be able to specify a test framework by class" do
53
+ class TestRunner
54
+ framework SomeTestFramework
55
+ end
56
+
57
+ TestRunner.framework.should eql SomeTestFramework
58
+ @runner.framework.should eql SomeTestFramework
59
+ end
60
+
61
+ it "should be able to specify middleware by alias" do
62
+ class TestRunner
63
+ middleware :some_middleware, :more_middleware
64
+ end
65
+
66
+ TestRunner.middleware.should eql [SomeMiddleware, SomeMoreMiddleware]
67
+ @runner.middleware.should eql [SomeMiddleware, SomeMoreMiddleware]
68
+ end
69
+
70
+ context "#run" do
71
+ it "should accept options and put them in the env hash" do
72
+ framework = SomeTestFramework.new
73
+ @runner.framework_instance = framework
74
+ @runner.run :foo => 'bar'
75
+ framework.env[:foo].should == 'bar'
76
+ end
77
+ end
78
+
79
+ context "just created" do
80
+ it "should have a nil status" do
81
+ @runner.status.should be_nil
82
+ end
83
+ end
84
+
85
+ context "with a test framework defined" do
86
+ before do
87
+ @runner.framework = SampleFramework
88
+ end
89
+
90
+ context "after running" do
91
+ before do
92
+ test_path = File.join(File.dirname(__FILE__), "sample_tests")
93
+ @runner.run :path => test_path
94
+ end
95
+
96
+ it "should have a status" do
97
+ @runner.status.should_not be_nil
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,33 @@
1
+ # A sample Testify framework intended to be used while testing Testify. A
2
+ # "test" consists of a line in the file, which should contain the status
3
+ # and optionally a colon and a message.
4
+ #
5
+ # Example test file:
6
+ # fail:The thing is not in the place.
7
+ # success
8
+ # pending:Need to implement cat napkins.
9
+ # success
10
+ #
11
+ class SampleFramework
12
+ include Testify::Framework
13
+
14
+ aka :sample
15
+
16
+ # Run the tests.
17
+ #
18
+ def call (env)
19
+ results = []
20
+
21
+ files(env).each do |file|
22
+ line_number = 0
23
+ File.open(file).each_line do |line|
24
+ line_number += 1
25
+ (status, message) = line.split(':')
26
+ results.push Testify::TestResult.new(:status => status.to_sym, :message => message, :file => file, :line => line_number)
27
+ end
28
+ end
29
+
30
+ results
31
+ end
32
+
33
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe "Something broken" do
4
+ it "should fail" do
5
+ true.should be false
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Something that sorta works but is broken in parts" do
4
+ it "should pass some things" do
5
+ true.should be true
6
+ end
7
+
8
+ it "should fail others" do
9
+ "foo".should be "bar"
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Something that works" do
4
+ it "should pass" do
5
+ true.should be true
6
+ end
7
+
8
+ it "should still pass" do
9
+ "foo".should == "foo"
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec'
2
+ require 'spec/autorun'
3
+
4
+ Spec::Runner.configure do |config|
5
+ end
@@ -1,9 +1,14 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__))
2
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
- require 'testify'
4
- require 'spec'
5
- require 'spec/autorun'
1
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'testify')
2
+ require_relative '../lib/testify'
3
+ require_relative 'sample_framework'
4
+ require 'rspec'
6
5
 
7
- Spec::Runner.configure do |config|
8
-
6
+ RSpec.configure do |config|
7
+ end
8
+
9
+ # Doesn't work for anything inside a module (eg, if you try to remove
10
+ # Testify::Framework::RSpec this will totally blow up).
11
+ def destroy_class ( klass )
12
+ klass = klass.name.to_s if klass.kind_of? Class
13
+ Object.class_exec { remove_const klass } if Object.const_defined? klass
9
14
  end
@@ -0,0 +1,11 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+
3
+ describe "Testify::TestResult" do
4
+ it "should be instantializable with a hash of attributes" do
5
+ res = Testify::TestResult.new(:file => 'woo_tests.rb', :line => 42, :status => :error, :message => "Your test asploded.")
6
+ res.status.should == :error
7
+ res.message.should == "Your test asploded."
8
+ res.file.should == 'woo_tests.rb'
9
+ res.line.should == 42
10
+ end
11
+ end
@@ -1,7 +1,23 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
2
 
3
3
  describe "Testify" do
4
- it "fails" do
5
- fail "hey buddy, you should probably rename this file and start specing for real"
4
+
5
+ context '.env_defaults' do
6
+ it "should provide an env hash with some default values" do
7
+ defaults = Testify.env_defaults
8
+
9
+ # Verify the values on these ones
10
+ defaults[:testify_version].should == Testify.version
11
+ defaults[:hooks].should == { :before_all => [], :after_all => [], :before_each => [], :after_each => [], :after_status => {} }
12
+ end
6
13
  end
14
+
15
+ context '.version' do
16
+ it "should return an array of three integers" do
17
+ version = Testify.version
18
+ version.should have(3).parts
19
+ version.each { |n| n.should be_an Integer }
20
+ end
21
+ end
22
+
7
23
  end
metadata CHANGED
@@ -1,28 +1,61 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: testify
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ prerelease:
5
+ version: 1.0.0
5
6
  platform: ruby
6
7
  authors:
7
8
  - John Hyland
8
- - Emily Price
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-11-02 00:00:00 -05:00
14
- default_executable:
13
+ date: 2011-10-31 00:00:00 Z
15
14
  dependencies:
16
15
  - !ruby/object:Gem::Dependency
17
- name: rspec
16
+ name: classy
17
+ requirement: &id001 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0"
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: jeweler
28
+ requirement: &id002 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
18
34
  type: :development
19
- version_requirement:
20
- version_requirements: !ruby/object:Gem::Requirement
35
+ prerelease: false
36
+ version_requirements: *id002
37
+ - !ruby/object:Gem::Dependency
38
+ name: classy
39
+ requirement: &id003 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: 1.0.0
45
+ type: :runtime
46
+ prerelease: false
47
+ version_requirements: *id003
48
+ - !ruby/object:Gem::Dependency
49
+ name: rspec
50
+ requirement: &id004 !ruby/object:Gem::Requirement
51
+ none: false
21
52
  requirements:
22
53
  - - ">="
23
54
  - !ruby/object:Gem::Version
24
55
  version: 1.2.9
25
- version:
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: *id004
26
59
  description:
27
60
  email: github@djspinmonkey.com
28
61
  executables: []
@@ -34,42 +67,62 @@ extra_rdoc_files:
34
67
  - README.rdoc
35
68
  files:
36
69
  - .document
37
- - .gitignore
70
+ - .rspec
71
+ - Gemfile
38
72
  - LICENSE
39
73
  - README.rdoc
40
74
  - Rakefile
75
+ - VERSION
76
+ - lib/framework.rb
77
+ - lib/middleware.rb
78
+ - lib/runner.rb
79
+ - lib/test_result.rb
41
80
  - lib/testify.rb
42
- - spec/spec.opts
81
+ - samples/README
82
+ - samples/awesome_runner.rb
83
+ - samples/awesome_test_framework.rb
84
+ - samples/awesome_tests/asplode.aws
85
+ - samples/awesome_tests/failing.aws
86
+ - samples/awesome_tests/passing.aws
87
+ - samples/dots.rb
88
+ - samples/summary.rb
89
+ - spec/framework_spec.rb
90
+ - spec/middleware_spec.rb
91
+ - spec/runner_spec.rb
92
+ - spec/sample_framework.rb
93
+ - spec/sample_tests/failing_tests
94
+ - spec/sample_tests/mixed_tests
95
+ - spec/sample_tests/passing_tests
96
+ - spec/sample_tests/test_helper
43
97
  - spec/spec_helper.rb
98
+ - spec/test_result_spec.rb
44
99
  - spec/testify_spec.rb
45
- has_rdoc: true
46
100
  homepage: http://github.com/djspinmonkey/testify
47
101
  licenses: []
48
102
 
49
103
  post_install_message:
50
- rdoc_options:
51
- - --charset=UTF-8
104
+ rdoc_options: []
105
+
52
106
  require_paths:
53
107
  - lib
54
108
  required_ruby_version: !ruby/object:Gem::Requirement
109
+ none: false
55
110
  requirements:
56
111
  - - ">="
57
112
  - !ruby/object:Gem::Version
58
113
  version: "0"
59
- version:
60
114
  required_rubygems_version: !ruby/object:Gem::Requirement
115
+ none: false
61
116
  requirements:
62
117
  - - ">="
63
118
  - !ruby/object:Gem::Version
64
119
  version: "0"
65
- version:
66
120
  requirements: []
67
121
 
68
122
  rubyforge_project:
69
- rubygems_version: 1.3.5
123
+ rubygems_version: 1.8.6
70
124
  signing_key:
71
125
  specification_version: 3
72
126
  summary: Testify is a test framework framework. Think "Rack for testing."
73
- test_files:
74
- - spec/spec_helper.rb
75
- - spec/testify_spec.rb
127
+ test_files: []
128
+
data/.gitignore DELETED
@@ -1,21 +0,0 @@
1
- ## MAC OS
2
- .DS_Store
3
-
4
- ## TEXTMATE
5
- *.tmproj
6
- tmtags
7
-
8
- ## EMACS
9
- *~
10
- \#*
11
- .\#*
12
-
13
- ## VIM
14
- *.swp
15
-
16
- ## PROJECT::GENERAL
17
- coverage
18
- rdoc
19
- pkg
20
-
21
- ## PROJECT::SPECIFIC
@@ -1 +0,0 @@
1
- --color