Class: Buildr::TestTask

Inherits:
Rake::Task show all
Defined in:
lib/buildr/core/test.rb

Overview

The test task controls the entire test lifecycle.

You can use the test task in three ways. You can access and configure specific test tasks, e.g. enhance the #compile task, or run code during #setup/#teardown.

You can use convenient methods that handle the most common settings. For example, add dependencies using #with, or include only specific tests using #include.

You can also enhance this task directly. This task will first execute the #compile task, followed by the #setup task, run the unit tests, any other enhancements, and end by executing #teardown.

The test framework is determined based on the available test files, for example, if the test cases are written in Java, then JUnit is selected as the test framework. You can also select a specific test framework, for example, to use TestNG instead of JUnit:

test.using :testng

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Rake::Task

#invoke, #invoke_with_call_chain

Constructor Details

#initialize(*args) ⇒ TestTask

:nodoc:



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/buildr/core/test.rb', line 223

def initialize(*args) #:nodoc:
  super
  @dependencies = FileList[]
  @include = []
  @exclude = []
  @forced_need = false
  parent_task = Project.parent_task(name)
  if parent_task.respond_to?(:options)
    @options = OpenObject.new { |hash, key| hash[key] = parent_task.options[key].clone rescue hash[key] = parent_task.options[key] }
  else
    @options = OpenObject.new(default_options)
  end

  unless ENV["IGNORE_BUILDFILE"] =~ /(true)|(yes)/i
    enhance [ application.buildfile.name ]
    enhance application.buildfile.prerequisites
  end
  enhance do
    run_tests if framework
  end
end

Instance Attribute Details

#dependenciesObject

The dependencies used for running the tests. Includes the compiled files (compile.target) and their dependencies. Will also include anything you pass to #with, shared between the testing compile and run dependencies.



248
249
250
# File 'lib/buildr/core/test.rb', line 248

def dependencies
  @dependencies
end

#failed_testsObject (readonly)

After running the task, returns all the tests that failed, empty array if all tests passed.



413
414
415
# File 'lib/buildr/core/test.rb', line 413

def failed_tests
  @failed_tests
end

#forced_needObject

Whether the tests are forced



477
478
479
# File 'lib/buildr/core/test.rb', line 477

def forced_need
  @forced_need
end

#optionsObject (readonly)

Returns various test options.



333
334
335
# File 'lib/buildr/core/test.rb', line 333

def options
  @options
end

#passed_testsObject (readonly)

After running the task, returns all the tests that passed, empty array if no tests passed.



415
416
417
# File 'lib/buildr/core/test.rb', line 415

def passed_tests
  @passed_tests
end

#projectObject (readonly)

The project this task belongs to.



474
475
476
# File 'lib/buildr/core/test.rb', line 474

def project
  @project
end

#testsObject (readonly)

After running the task, returns all tests selected to run, based on availability and include/exclude pattern.



411
412
413
# File 'lib/buildr/core/test.rb', line 411

def tests
  @tests
end

Class Method Details

.clearObject

Used by the test/integration rule to clear all previously included/excluded tests.



187
188
189
190
191
# File 'lib/buildr/core/test.rb', line 187

def clear()
  Project.projects.each do |project|
    project.test.send :clear
  end
end

.exclude(excludes) ⇒ Object

Used by the test/integration to exclude specific tests



203
204
205
206
207
208
209
# File 'lib/buildr/core/test.rb', line 203

def exclude(excludes)
  excludes = wildcardify(Array(excludes))
  Project.projects.each do |project|
    project.test.send :exclude, *excludes if excludes.size > 0
    project.test.send :forced_need=, true
  end
end

.include(includes) ⇒ Object

Used by the test/integration to include specific tests



194
195
196
197
198
199
200
# File 'lib/buildr/core/test.rb', line 194

def include(includes)
  includes = wildcardify(Array(includes))
  Project.projects.each do |project|
    project.test.send :include, *includes if includes.size > 0
    project.test.send :forced_need=, true
  end
end

.only_run(tests) ⇒ Object

Used by the test/integration rule to only run tests that match the specified names.



172
173
174
175
176
177
# File 'lib/buildr/core/test.rb', line 172

def only_run(tests) #:nodoc:
  tests = wildcardify(tests)
  # Since the tests may reside in a sub-project, we need to set the include/exclude pattern on
  # all sub-projects, but only invoke test on the local project.
  Project.projects.each { |project| project.test.send :only_run, tests }
end

.only_run_failedObject

Used by the test/integration rule to only run tests that failed the last time.



180
181
182
183
184
# File 'lib/buildr/core/test.rb', line 180

def only_run_failed() #:nodoc:
  # Since the tests may reside in a sub-project, we need to set the include/exclude pattern on
  # all sub-projects, but only invoke test on the local project.
  Project.projects.each { |project| project.test.send :only_run_failed }
end

.run_local_tests(integration) ⇒ Object

Used by the local test and integration tasks to a) Find the local project(s), b) Find all its sub-projects and narrow down to those that have either unit or integration tests, c) Run all the (either unit or integration) tests, and d) Ignore failure if necessary.



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/buildr/core/test.rb', line 151

def run_local_tests(integration) #:nodoc:
  Project.local_projects do |project|
    # !(foo ^ bar) tests for equality and accepts nil as false (and select is less obfuscated than reject on ^).
    projects = ([project] + project.projects).select { |project| !(project.test.options[:integration] ^ integration) }
    projects.each do |project|
      info "Testing #{project.name}"
      # Invoke the prerequisites outside of the rescue block, otherwise errors converging
      # the prerequisites are swallowed (and treated like failed test results). Moving the
      # code outside means problems such as test code that does not compile will result in a
      # build failure even if Buildr.options.test is set to :all
      project.test.prerequisites.each{|p|p.is_a?(String) ? file(p).invoke : p.invoke}
      begin
        project.test.invoke
      rescue
        raise unless Buildr.options.test == :all
      end
    end
  end
end

Instance Method Details

#classesObject

Deprecated: Use tests instead.



405
406
407
408
# File 'lib/buildr/core/test.rb', line 405

def classes
  Buildr.application.deprecated 'Call tests instead of classes'
  tests
end

#classpathObject

Deprecated: Use dependencies instead.



251
252
253
254
# File 'lib/buildr/core/test.rb', line 251

def classpath
  Buildr.application.deprecated 'Use dependencies instead.'
  @dependencies
end

#classpath=(artifacts) ⇒ Object

Deprecated: Use dependencies= instead.



257
258
259
260
# File 'lib/buildr/core/test.rb', line 257

def classpath=(artifacts)
  Buildr.application.deprecated 'Use dependencies= instead.'
  @dependencies = artifacts
end

#clearObject

Clear all test includes and excludes and returns self



398
399
400
401
402
# File 'lib/buildr/core/test.rb', line 398

def clear
  @include = []
  @exclude = []
  self
end

#compile(*sources, &block) ⇒ Object

:call-seq:

compile(*sources) => CompileTask
compile(*sources) { |task| .. } => CompileTask

The compile task is similar to the Project’s compile task. However, it compiles all files found in the src/test/source directory into the target/test/code directory. This task is executed by the test task before running any tests.

Once the project definition is complete, all dependencies from the regular compile task are copied over, so you only need to specify dependencies specific to your tests. You can do so by calling #with on the test task. The dependencies used here are also copied over to the junit task.



289
290
291
# File 'lib/buildr/core/test.rb', line 289

def compile(*sources, &block)
  @project.task('test:compile').from(sources).enhance &block
end

#default_optionsObject

Default options already set on each test task.



219
220
221
# File 'lib/buildr/core/test.rb', line 219

def default_options
  { :fail_on_failure=>true, :fork=>:once, :properties=>{}, :environment=>{} }
end

#exclude(*names) ⇒ Object

:call-seq:

exclude(*names) => self

Exclude the specified tests. This method accepts multiple arguments and returns self. See #include for the type of arguments you can use.



392
393
394
395
# File 'lib/buildr/core/test.rb', line 392

def exclude(*names)
  @exclude += names
  self
end

#execute(args) ⇒ Object

:nodoc:



262
263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/buildr/core/test.rb', line 262

def execute(args) #:nodoc:
  if Buildr.options.test == false
    trace "Skipping tests for #{project.name}"
    return
  end
  setup.invoke
  begin
    super
  rescue RuntimeError
    raise if options[:fail_on_failure] && Buildr.options.test != :all
  ensure
    teardown.invoke
  end
end

#failures_toObject

:call-seq:

failures_to => file

We record the list of failed tests for the current framework in this file.



450
451
452
# File 'lib/buildr/core/test.rb', line 450

def failures_to
  @failures_to ||= file(@project.path_to(:target, "#{framework}-failed")=>self)
end

#frameworkObject

:call-seq:

framework => symbol

Returns the test framework, e.g. :junit, :testng.



421
422
423
424
425
426
427
428
429
430
431
# File 'lib/buildr/core/test.rb', line 421

def framework
  unless @framework
    # Start with all frameworks that apply (e.g. JUnit and TestNG for Java),
    # and pick the first (default) one, unless already specified in parent project.
    candidates = TestFramework.frameworks.select { |cls| cls.applies_to?(@project) }
    candidate = @project.parent && candidates.detect { |framework| framework.to_sym == @project.parent.test.framework } ||
      candidates.first
    self.framework = candidate if candidate
  end
  @framework && @framework.class.to_sym
end

#include(*names) ⇒ Object

:call-seq:

include(*names) => self

Include only the specified tests. Unless specified, the default is to include all tests identified by the test framework. This method accepts multiple arguments and returns self.

Tests are specified by their full name, but you can use glob patterns to select multiple tests, for example:

test.include 'com.example.FirstTest'  # FirstTest only
test.include 'com.example.*'          # All tests under com/example
test.include 'com.example.Module*'    # All tests starting with Module
test.include '*.{First,Second}Test'   # FirstTest, SecondTest


382
383
384
385
# File 'lib/buildr/core/test.rb', line 382

def include(*names)
  @include += names
  self
end

#last_failuresObject

:call-seq:

last_failures => array

We read the last test failures if any and return them.



459
460
461
# File 'lib/buildr/core/test.rb', line 459

def last_failures
  @last_failures ||= failures_to.exist? ? File.read(failures_to.to_s).split("\n") : []
end

#last_successful_run_fileObject

The path to the file that stores the time stamp of the last successful test run.



464
465
466
# File 'lib/buildr/core/test.rb', line 464

def last_successful_run_file #:nodoc:
  File.join(report_to.to_s, 'last_successful_run')
end

#report_toObject

:call-seq:

report_to => file

Test frameworks that can produce reports, will write them to this directory.

This is framework dependent, so unless you use the default test framework, call this method after setting the test framework.



440
441
442
# File 'lib/buildr/core/test.rb', line 440

def report_to
  @report_to ||= file(@project.path_to(:reports, framework)=>self)
end

#resources(*prereqs, &block) ⇒ Object

:call-seq:

resources(*prereqs) => ResourcesTask
resources(*prereqs) { |task| .. } => ResourcesTask

Executes by the #compile task to copy resource files over. See Project#resources.



298
299
300
# File 'lib/buildr/core/test.rb', line 298

def resources(*prereqs, &block)
  @project.task('test:resources').enhance prereqs, &block
end

#setup(*prereqs, &block) ⇒ Object

:call-seq:

setup(*prereqs) => task
setup(*prereqs) { |task| .. } => task

Returns the setup task. The setup task is executed at the beginning of the test task, after compiling the test files.



308
309
310
# File 'lib/buildr/core/test.rb', line 308

def setup(*prereqs, &block)
  @project.task('test:setup').enhance prereqs, &block
end

#teardown(*prereqs, &block) ⇒ Object

:call-seq:

teardown(*prereqs) => task
teardown(*prereqs) { |task| .. } => task

Returns the teardown task. The teardown task is executed at the end of the test task.



317
318
319
# File 'lib/buildr/core/test.rb', line 317

def teardown(*prereqs, &block)
  @project.task('test:teardown').enhance prereqs, &block
end

#timestampObject

The time stamp of the last successful test run. Or Rake::EARLY if no successful test run recorded.



469
470
471
# File 'lib/buildr/core/test.rb', line 469

def timestamp #:nodoc:
  File.exist?(last_successful_run_file) ? File.mtime(last_successful_run_file) : Rake::EARLY
end

#using(*args) ⇒ Object

:call-seq:

using(options) => self

Sets various test options from a hash and returns self. For example:

test.using :fork=>:each, :properties=>{ 'url'=>'http://localhost:8080' }

Can also be used to select the test framework, or to run these tests as integration tests. For example:

test.using :testng
test.using :integration

The :fail_on_failure option specifies whether the task should fail if any of the tests fail (default), or should report the failures but continue running the build (when set to false).

All other options depend on the capability of the test framework. These options should be used the same way across all frameworks that support them:

  • :fork – Fork once for each project (:once, default), for each test in each

    project (:each), or don't fork at all (false).
    
  • :properties – Properties pass to the test, e.g. in Java as system properties.

  • :environment – Environment variables. This hash is made available in the

    form of environment variables.
    


357
358
359
360
361
362
363
364
365
366
367
# File 'lib/buildr/core/test.rb', line 357

def using(*args)
  args.pop.each { |key, value| options[key.to_sym] = value } if Hash === args.last
  args.each do |name|
    if TestFramework.has?(name)
      self.framework = name
    elsif name == :integration
      options[:integration] = true
    end
  end
  self
end

#with(*artifacts) ⇒ Object

:call-seq:

with(*specs) => self

Specify artifacts (specs, tasks, files, etc) to include in the dependencies list when compiling and running tests.



326
327
328
329
330
# File 'lib/buildr/core/test.rb', line 326

def with(*artifacts)
  @dependencies |= Buildr.artifacts(artifacts.flatten).uniq
  compile.with artifacts
  self
end