| Name | Total Lines | Lines of Code | Total Coverage | Code Coverage |
|---|---|---|---|---|
| lib/buildr/core/test.rb | 843 | 427 | 19.45%
|
26.23%
|
Code reported as executed by Ruby looks like this...and this: this line is also marked as covered.Lines considered as run by rcov, but not reported by Ruby, look like this,and this: these lines were inferred by rcov (using simple heuristics).Finally, here's a line marked as not executed.
1 # Licensed to the Apache Software Foundation (ASF) under one or more |
2 # contributor license agreements. See the NOTICE file distributed with this |
3 # work for additional information regarding copyright ownership. The ASF |
4 # licenses this file to you under the Apache License, Version 2.0 (the |
5 # "License"); you may not use this file except in compliance with the License. |
6 # You may obtain a copy of the License at |
7 # |
8 # http://www.apache.org/licenses/LICENSE-2.0 |
9 # |
10 # Unless required by applicable law or agreed to in writing, software |
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
13 # License for the specific language governing permissions and limitations under |
14 # the License. |
15 |
16 |
17 require 'buildr/core/project' |
18 require 'buildr/core/build' |
19 require 'buildr/core/compile' |
20 |
21 |
22 module Buildr |
23 |
24 # The underlying test framework used by TestTask. |
25 # To add a new test framework, extend TestFramework::Base and add your framework using: |
26 # Buildr::TestFramework << MyFramework |
27 module TestFramework |
28 |
29 class << self |
30 |
31 # Returns true if the specified test framework exists. |
32 def has?(name) |
33 frameworks.any? { |framework| framework.to_sym == name.to_sym } |
34 end |
35 |
36 # Select a test framework by its name. |
37 def select(name) |
38 frameworks.detect { |framework| framework.to_sym == name.to_sym } |
39 end |
40 |
41 # Identify which test framework applies for this project. |
42 def select_from(project) |
43 # Look for a suitable test framework based on the compiled language, |
44 # which may return multiple candidates, e.g. JUnit and TestNG for Java. |
45 # Pick the one used in the parent project, if not, whichever comes first. |
46 candidates = frameworks.select { |framework| framework.applies_to?(project) } |
47 parent = project.parent |
48 parent && candidates.detect { |framework| framework.to_sym == parent.test.framework } || candidates.first |
49 end |
50 |
51 # Adds a test framework to the list of supported frameworks. |
52 # |
53 # For example: |
54 # Buildr::TestFramework << Buildr::JUnit |
55 def add(framework) |
56 @frameworks ||= [] |
57 @frameworks |= [framework] |
58 end |
59 alias :<< :add |
60 |
61 # Returns a list of available test frameworks. |
62 def frameworks |
63 @frameworks ||= [] |
64 end |
65 |
66 end |
67 |
68 # Base class for all test frameworks, with common functionality. Extend and over-ride as you see fit |
69 # (see JUnit as an example). |
70 class Base |
71 |
72 class << self |
73 |
74 # The framework's identifier (e.g. :junit). Inferred from the class name. |
75 def to_sym |
76 @symbol ||= name.split('::').last.downcase.to_sym |
77 end |
78 |
79 # Returns true if this framework applies to the current project. For example, JUnit returns |
80 # true if the tests are written in Java. |
81 def applies_to?(project) |
82 raise 'Not implemented' |
83 end |
84 |
85 # Returns a list of dependencies for this framework. Default is an empty list, |
86 # override to add dependencies. |
87 def dependencies |
88 @dependencies ||= [] |
89 end |
90 |
91 end |
92 |
93 # Construct a new test framework with the specified options. Note that options may |
94 # change before the framework is run. |
95 def initialize(test_task, options) |
96 @options = options |
97 @task = test_task |
98 end |
99 |
100 # Options for this test framework. |
101 attr_reader :options |
102 # The test task we belong to |
103 attr_reader :task |
104 |
105 # Returns a list of dependenices for this framework. Defaults to calling the #dependencies |
106 # method on the class. |
107 def dependencies |
108 self.class.dependencies |
109 end |
110 |
111 # TestTask calls this method to return a list of test names that can be run in this project. |
112 # It then applies the include/exclude patterns to arrive at the list of tests that will be |
113 # run, and call the #run method with that list. |
114 # |
115 # This method should return a list suitable for using with the #run method, but also suitable |
116 # for the user to manage. For example, JUnit locates all the tests in the test.compile.target |
117 # directory, and returns the class names, which are easier to work with than file names. |
118 def tests(dependencies) |
119 raise 'Not implemented' |
120 end |
121 |
122 # TestTask calls this method to run the named (and only those) tests. This method returns |
123 # the list of tests that ran successfully. |
124 def run(tests, dependencies) |
125 raise 'Not implemented' |
126 end |
127 |
128 end |
129 |
130 end |
131 |
132 |
133 # The test task controls the entire test lifecycle. |
134 # |
135 # You can use the test task in three ways. You can access and configure specific test tasks, |
136 # e.g. enhance the #compile task, or run code during #setup/#teardown. |
137 # |
138 # You can use convenient methods that handle the most common settings. For example, |
139 # add dependencies using #with, or include only specific tests using #include. |
140 # |
141 # You can also enhance this task directly. This task will first execute the #compile task, followed |
142 # by the #setup task, run the unit tests, any other enhancements, and end by executing #teardown. |
143 # |
144 # The test framework is determined based on the available test files, for example, if the test |
145 # cases are written in Java, then JUnit is selected as the test framework. You can also select |
146 # a specific test framework, for example, to use TestNG instead of JUnit: |
147 # test.using :testng |
148 class TestTask < Rake::Task |
149 |
150 class << self |
151 |
152 # Used by the local test and integration tasks to |
153 # a) Find the local project(s), |
154 # b) Find all its sub-projects and narrow down to those that have either unit or integration tests, |
155 # c) Run all the (either unit or integration) tests, and |
156 # d) Ignore failure if necessary. |
157 def run_local_tests(integration) #:nodoc: |
158 Project.local_projects do |project| |
159 # !(foo ^ bar) tests for equality and accepts nil as false (and select is less obfuscated than reject on ^). |
160 projects = ([project] + project.projects).select { |project| !(project.test.options[:integration] ^ integration) } |
161 projects.each do |project| |
162 info "Testing #{project.name}" |
163 begin |
164 project.test.invoke |
165 rescue |
166 raise unless Buildr.options.test == :all |
167 end |
168 end |
169 end |
170 end |
171 |
172 # Used by the test/integration rule to only run tests that match the specified names. |
173 def only_run(tests) #:nodoc: |
174 tests = wildcardify(tests) |
175 # Since the tests may reside in a sub-project, we need to set the include/exclude pattern on |
176 # all sub-projects, but only invoke test on the local project. |
177 Project.projects.each { |project| project.test.send :only_run, tests } |
178 end |
179 |
180 # Used by the test/integration rule to only run tests that failed the last time. |
181 def only_run_failed() #:nodoc: |
182 # Since the tests may reside in a sub-project, we need to set the include/exclude pattern on |
183 # all sub-projects, but only invoke test on the local project. |
184 Project.projects.each { |project| project.test.send :only_run_failed } |
185 end |
186 |
187 # Used by the test/integration rule to clear all previously included/excluded tests. |
188 def clear() |
189 Project.projects.each do |project| |
190 project.test.send :clear |
191 end |
192 end |
193 |
194 # Used by the test/integration to include specific tests |
195 def include(includes) |
196 includes = wildcardify(Array(includes)) |
197 Project.projects.each do |project| |
198 project.test.send :include, *includes if includes.size > 0 |
199 project.test.send :forced_need=, true |
200 end |
201 end |
202 |
203 # Used by the test/integration to exclude specific tests |
204 def exclude(excludes) |
205 excludes = wildcardify(Array(excludes)) |
206 Project.projects.each do |project| |
207 project.test.send :exclude, *excludes if excludes.size > 0 |
208 project.test.send :forced_need=, true |
209 end |
210 end |
211 |
212 private |
213 |
214 def wildcardify(strings) |
215 strings.map { |name| name =~ /\*/ ? name : "*#{name}*" } |
216 end |
217 end |
218 |
219 # Default options already set on each test task. |
220 def default_options |
221 { :fail_on_failure=>true, :fork=>:once, :properties=>{}, :environment=>{} } |
222 end |
223 |
224 def initialize(*args) #:nodoc: |
225 super |
226 @dependencies = FileList[] |
227 @include = [] |
228 @exclude = [] |
229 @forced_need = false |
230 parent_task = Project.parent_task(name) |
231 if parent_task.respond_to?(:options) |
232 @options = OpenObject.new { |hash, key| hash[key] = parent_task.options[key].clone rescue hash[key] = parent_task.options[key] } |
233 else |
234 @options = OpenObject.new(default_options) |
235 end |
236 |
237 unless ENV["IGNORE_BUILDFILE"] =~ /(true)|(yes)/i |
238 enhance [ application.buildfile.name ] |
239 enhance application.buildfile.prerequisites |
240 end |
241 enhance do |
242 run_tests if framework |
243 end |
244 end |
245 |
246 # The dependencies used for running the tests. Includes the compiled files (compile.target) |
247 # and their dependencies. Will also include anything you pass to #with, shared between the |
248 # testing compile and run dependencies. |
249 attr_accessor :dependencies |
250 |
251 # *Deprecated*: Use dependencies instead. |
252 def classpath |
253 Buildr.application.deprecated 'Use dependencies instead.' |
254 @dependencies |
255 end |
256 |
257 # *Deprecated*: Use dependencies= instead. |
258 def classpath=(artifacts) |
259 Buildr.application.deprecated 'Use dependencies= instead.' |
260 @dependencies = artifacts |
261 end |
262 |
263 def execute(args) #:nodoc: |
264 if Buildr.options.test == false |
265 info "Skipping tests for #{project.name}" |
266 return |
267 end |
268 setup.invoke |
269 begin |
270 super |
271 rescue RuntimeError |
272 raise if options[:fail_on_failure] && Buildr.options.test != :all |
273 ensure |
274 teardown.invoke |
275 end |
276 end |
277 |
278 # :call-seq: |
279 # compile(*sources) => CompileTask |
280 # compile(*sources) { |task| .. } => CompileTask |
281 # |
282 # The compile task is similar to the Project's compile task. However, it compiles all |
283 # files found in the src/test/{source} directory into the target/test/{code} directory. |
284 # This task is executed by the test task before running any tests. |
285 # |
286 # Once the project definition is complete, all dependencies from the regular |
287 # compile task are copied over, so you only need to specify dependencies |
288 # specific to your tests. You can do so by calling #with on the test task. |
289 # The dependencies used here are also copied over to the junit task. |
290 def compile(*sources, &block) |
291 @project.task('test:compile').from(sources).enhance &block |
292 end |
293 |
294 # :call-seq: |
295 # resources(*prereqs) => ResourcesTask |
296 # resources(*prereqs) { |task| .. } => ResourcesTask |
297 # |
298 # Executes by the #compile task to copy resource files over. See Project#resources. |
299 def resources(*prereqs, &block) |
300 @project.task('test:resources').enhance prereqs, &block |
301 end |
302 |
303 # :call-seq: |
304 # setup(*prereqs) => task |
305 # setup(*prereqs) { |task| .. } => task |
306 # |
307 # Returns the setup task. The setup task is executed at the beginning of the test task, |
308 # after compiling the test files. |
309 def setup(*prereqs, &block) |
310 @project.task('test:setup').enhance prereqs, &block |
311 end |
312 |
313 # :call-seq: |
314 # teardown(*prereqs) => task |
315 # teardown(*prereqs) { |task| .. } => task |
316 # |
317 # Returns the teardown task. The teardown task is executed at the end of the test task. |
318 def teardown(*prereqs, &block) |
319 @project.task('test:teardown').enhance prereqs, &block |
320 end |
321 |
322 # :call-seq: |
323 # with(*specs) => self |
324 # |
325 # Specify artifacts (specs, tasks, files, etc) to include in the dependencies list |
326 # when compiling and running tests. |
327 def with(*artifacts) |
328 @dependencies |= Buildr.artifacts(artifacts.flatten).uniq |
329 compile.with artifacts |
330 self |
331 end |
332 |
333 # Returns various test options. |
334 attr_reader :options |
335 |
336 # :call-seq: |
337 # using(options) => self |
338 # |
339 # Sets various test options from a hash and returns self. For example: |
340 # test.using :fork=>:each, :properties=>{ 'url'=>'http://localhost:8080' } |
341 # |
342 # Can also be used to select the test framework, or to run these tests as |
343 # integration tests. For example: |
344 # test.using :testng |
345 # test.using :integration |
346 # |
347 # The :fail_on_failure option specifies whether the task should fail if |
348 # any of the tests fail (default), or should report the failures but continue |
349 # running the build (when set to false). |
350 # |
351 # All other options depend on the capability of the test framework. These options |
352 # should be used the same way across all frameworks that support them: |
353 # * :fork -- Fork once for each project (:once, default), for each test in each |
354 # project (:each), or don't fork at all (false). |
355 # * :properties -- Properties pass to the test, e.g. in Java as system properties. |
356 # * :environment -- Environment variables. This hash is made available in the |
357 # form of environment variables. |
358 def using(*args) |
359 args.pop.each { |key, value| options[key.to_sym] = value } if Hash === args.last |
360 args.each do |name| |
361 if TestFramework.has?(name) |
362 self.framework = name |
363 elsif name == :integration |
364 options[:integration] = true |
365 else |
366 Buildr.application.deprecated "Please replace with using(:#{name}=>true)" |
367 options[name.to_sym] = true |
368 end |
369 end |
370 self |
371 end |
372 |
373 # :call-seq: |
374 # include(*names) => self |
375 # |
376 # Include only the specified tests. Unless specified, the default is to include |
377 # all tests identified by the test framework. This method accepts multiple arguments |
378 # and returns self. |
379 # |
380 # Tests are specified by their full name, but you can use glob patterns to select |
381 # multiple tests, for example: |
382 # test.include 'com.example.FirstTest' # FirstTest only |
383 # test.include 'com.example.*' # All tests under com/example |
384 # test.include 'com.example.Module*' # All tests starting with Module |
385 # test.include '*.{First,Second}Test' # FirstTest, SecondTest |
386 def include(*names) |
387 @include += names |
388 self |
389 end |
390 |
391 # :call-seq: |
392 # exclude(*names) => self |
393 # |
394 # Exclude the specified tests. This method accepts multiple arguments and returns self. |
395 # See #include for the type of arguments you can use. |
396 def exclude(*names) |
397 @exclude += names |
398 self |
399 end |
400 |
401 # Clear all test includes and excludes and returns self |
402 def clear |
403 @include = [] |
404 @exclude = [] |
405 self |
406 end |
407 |
408 # *Deprecated*: Use tests instead. |
409 def classes |
410 Buildr.application.deprecated 'Call tests instead of classes' |
411 tests |
412 end |
413 |
414 # After running the task, returns all tests selected to run, based on availability and include/exclude pattern. |
415 attr_reader :tests |
416 # After running the task, returns all the tests that failed, empty array if all tests passed. |
417 attr_reader :failed_tests |
418 # After running the task, returns all the tests that passed, empty array if no tests passed. |
419 attr_reader :passed_tests |
420 |
421 # :call-seq: |
422 # framework => symbol |
423 # |
424 # Returns the test framework, e.g. :junit, :testng. |
425 def framework |
426 unless @framework |
427 # Start with all frameworks that apply (e.g. JUnit and TestNG for Java), |
428 # and pick the first (default) one, unless already specified in parent project. |
429 candidates = TestFramework.frameworks.select { |cls| cls.applies_to?(@project) } |
430 candidate = @project.parent && candidates.detect { |framework| framework.to_sym == @project.parent.test.framework } || |
431 candidates.first |
432 self.framework = candidate if candidate |
433 end |
434 @framework && @framework.class.to_sym |
435 end |
436 |
437 # :call-seq: |
438 # report_to => file |
439 # |
440 # Test frameworks that can produce reports, will write them to this directory. |
441 # |
442 # This is framework dependent, so unless you use the default test framework, call this method |
443 # after setting the test framework. |
444 def report_to |
445 @report_to ||= file(@project.path_to(:reports, framework)=>self) |
446 end |
447 |
448 # :call-seq: |
449 # failures_to => file |
450 # |
451 # We record the list of failed tests for the current framework in this file. |
452 # |
453 # |
454 def failures_to |
455 @failures_to ||= file(@project.path_to(:target, "#{framework}-failed")=>self) |
456 end |
457 |
458 # :call-seq: |
459 # last_failures => array |
460 # |
461 # We read the last test failures if any and return them. |
462 # |
463 def last_failures |
464 @last_failures ||= failures_to.exist? ? File.read(failures_to.to_s).split("\n") : [] |
465 end |
466 |
467 # The path to the file that stores the time stamp of the last successful test run. |
468 def last_successful_run_file #:nodoc: |
469 File.join(report_to.to_s, 'last_successful_run') |
470 end |
471 |
472 # The time stamp of the last successful test run. Or Rake::EARLY if no successful test run recorded. |
473 def timestamp #:nodoc: |
474 File.exist?(last_successful_run_file) ? File.mtime(last_successful_run_file) : Rake::EARLY |
475 end |
476 |
477 # The project this task belongs to. |
478 attr_reader :project |
479 |
480 # Whether the tests are forced |
481 attr_accessor :forced_need |
482 |
483 protected |
484 |
485 def associate_with(project) |
486 @project = project |
487 end |
488 |
489 def framework=(name) |
490 cls = TestFramework.select(name) or raise ArgumentError, "No #{name} test framework available. Did you install it?" |
491 #cls.inherit_options.reject { |name| options.has_key?(name) }. |
492 # each { |name| options[name] = @parent_task.options[name] } if @parent_task.respond_to?(:options) |
493 @framework = cls.new(self, options) |
494 # Test framework dependency. |
495 with @framework.dependencies |
496 end |
497 |
498 # :call-seq: |
499 # include?(name) => boolean |
500 # |
501 # Returns true if the specified test name matches the inclusion/exclusion pattern. Used to determine |
502 # which tests to execute. |
503 def include?(name) |
504 ((@include.empty? && !@forced_need)|| @include.any? { |pattern| File.fnmatch(pattern, name) }) && |
505 !@exclude.any? { |pattern| File.fnmatch(pattern, name) } |
506 end |
507 |
508 # Runs the tests using the selected test framework. |
509 def run_tests |
510 dependencies = (Buildr.artifacts(self.dependencies + compile.dependencies) + [compile.target]).map(&:to_s).uniq |
511 rm_rf report_to.to_s |
512 rm_rf failures_to.to_s |
513 @tests = @framework.tests(dependencies).select { |test| include?(test) }.sort |
514 if @tests.empty? |
515 @passed_tests, @failed_tests = [], [] |
516 else |
517 info "Running tests in #{@project.name}" |
518 begin |
519 # set the baseDir system property if not set |
520 @framework.options[:properties] = { 'baseDir' => compile.target.to_s }.merge(@framework.options[:properties] || {}) |
521 @passed_tests = @framework.run(@tests, dependencies) |
522 rescue Exception=>ex |
523 error "Test framework error: #{ex.message}" |
524 error ex.backtrace.join("\n") if trace? |
525 @passed_tests = [] |
526 end |
527 @failed_tests = @tests - @passed_tests |
528 unless @failed_tests.empty? |
529 Buildr::write(failures_to.to_s, @failed_tests.join("\n")) |
530 error "The following tests failed:\n#{@failed_tests.join("\n")}" |
531 fail 'Tests failed!' |
532 end |
533 end |
534 record_successful_run unless @forced_need |
535 end |
536 |
537 # Call this method when a test run is successful to record the current system time. |
538 def record_successful_run #:nodoc: |
539 mkdir_p report_to.to_s |
540 touch last_successful_run_file |
541 end |
542 |
543 # Limit running tests to specific list. |
544 def only_run(tests) |
545 @include = Array(tests) |
546 @exclude.clear |
547 @forced_need = true |
548 end |
549 |
550 # Limit running tests to those who failed the last time. |
551 def only_run_failed() |
552 @include = Array(last_failures) |
553 @forced_need = true |
554 end |
555 |
556 def invoke_prerequisites(args, chain) #:nodoc: |
557 @prerequisites |= FileList[@dependencies.uniq] |
558 super |
559 end |
560 |
561 def needed? #:nodoc: |
562 latest_prerequisite = @prerequisites.map { |p| application[p, @scope] }.max { |a,b| a.timestamp<=>b.timestamp } |
563 needed = (timestamp == Rake::EARLY) || latest_prerequisite.timestamp > timestamp |
564 trace "Testing#{needed ? ' ' : ' not '}needed. " + |
565 "Latest prerequisite change: #{latest_prerequisite.timestamp} (#{latest_prerequisite.to_s}). " + |
566 "Last successful test run: #{timestamp}." |
567 return needed || @forced_need || Buildr.options.test == :all |
568 end |
569 end |
570 |
571 |
572 # The integration tests task. Buildr has one such task (see Buildr#integration) that runs |
573 # all tests marked with :integration=>true, and has a setup/teardown tasks separate from |
574 # the unit tests. |
575 class IntegrationTestsTask < Rake::Task |
576 |
577 def initialize(*args) #:nodoc: |
578 super |
579 @setup = task("#{name}:setup") |
580 @teardown = task("#{name}:teardown") |
581 enhance do |
582 info 'Running integration tests...' |
583 TestTask.run_local_tests true |
584 end |
585 end |
586 |
587 def execute(args) #:nodoc: |
588 setup.invoke |
589 begin |
590 super |
591 ensure |
592 teardown.invoke |
593 end |
594 end |
595 |
596 # :call-seq: |
597 # setup(*prereqs) => task |
598 # setup(*prereqs) { |task| .. } => task |
599 # |
600 # Returns the setup task. The setup task is executed before running the integration tests. |
601 def setup(*prereqs, &block) |
602 @setup.enhance prereqs, &block |
603 end |
604 |
605 # :call-seq: |
606 # teardown(*prereqs) => task |
607 # teardown(*prereqs) { |task| .. } => task |
608 # |
609 # Returns the teardown task. The teardown task is executed after running the integration tests. |
610 def teardown(*prereqs, &block) |
611 @teardown.enhance prereqs, &block |
612 end |
613 |
614 end |
615 |
616 |
617 # Methods added to Project to support compilation and running of tests. |
618 module Test |
619 |
620 include Extension |
621 |
622 first_time do |
623 desc 'Run all tests' |
624 task('test') { TestTask.run_local_tests false } |
625 |
626 desc 'Run failed tests' |
627 task('test:failed') { |
628 TestTask.only_run_failed |
629 task('test').invoke |
630 } |
631 |
632 # This rule takes a suffix and runs that tests in the current project. For example; |
633 # buildr test:MyTest |
634 # will run the test com.example.MyTest, if such a test exists for this project. |
635 # |
636 # If you want to run multiple test, separate them with a comma. You can also use glob |
637 # (* and ?) patterns to match multiple tests, see the TestTask#include method. |
638 rule /^test:.*$/ do |task| |
639 # The map works around a JRuby bug whereby the string looks fine, but fails in fnmatch. |
640 tests = task.name.scan(/test:(.*)/)[0][0].split(',').map(&:to_s) |
641 excludes, includes = tests.partition { |t| t =~ /^-/ } |
642 if excludes.empty? |
643 TestTask.only_run includes |
644 else |
645 # remove leading '-' |
646 excludes.map! { |t| t[1..-1] } |
647 |
648 TestTask.clear |
649 TestTask.include(includes.empty? ? ['*'] : includes) |
650 TestTask.exclude excludes |
651 end |
652 task('test').invoke |
653 end |
654 |
655 IntegrationTestsTask.define_task('integration') |
656 |
657 # Similar to test:[pattern] but for integration tests. |
658 rule /^integration:.*$/ do |task| |
659 unless task.name.split(':')[1] =~ /^(setup|teardown)$/ |
660 # The map works around a JRuby bug whereby the string looks fine, but fails in fnmatch. |
661 TestTask.only_run task.name[/integration:(.*)/, 1].split(',').map { |t| "#{t}" } |
662 task('integration').invoke |
663 end |
664 end |
665 |
666 end |
667 |
668 before_define(:test) do |project| |
669 # Define a recursive test task, and pass it a reference to the project so it can discover all other tasks. |
670 test = TestTask.define_task('test') |
671 test.send :associate_with, project |
672 |
673 # Similar to the regular resources task but using different paths. |
674 resources = ResourcesTask.define_task('test:resources') |
675 resources.send :associate_with, project, :test |
676 project.path_to(:source, :test, :resources).tap { |dir| resources.from dir if File.exist?(dir) } |
677 |
678 # We define a module inline that will inject cancelling the task if tests are skipped. |
679 module SkipIfNoTest |
680 |
681 def self.extended(base) |
682 base.instance_eval {alias :execute_before_skip_if_no_test :execute} |
683 base.instance_eval {alias :execute :execute_after_skip_if_no_test} |
684 end |
685 |
686 def execute_after_skip_if_no_test(args) #:nodoc: |
687 if Buildr.options.test == false |
688 trace "Skipping #{to_s} for #{project.name} as tests are skipped" |
689 return |
690 end |
691 execute_before_skip_if_no_test(args) |
692 end |
693 end |
694 |
695 # Similar to the regular compile task but using different paths. |
696 compile = CompileTask.define_task('test:compile'=>[project.compile, resources]) |
697 compile.extend SkipIfNoTest |
698 compile.send :associate_with, project, :test |
699 test.enhance [compile] |
700 |
701 # Define these tasks once, otherwise we may get a namespace error. |
702 test.setup ; test.teardown |
703 end |
704 |
705 |
706 |
707 after_define(:test => :compile) do |project| |
708 test = project.test |
709 # Dependency on compiled tests and resources. Dependencies added using with. |
710 test.dependencies.concat [test.compile.target, test.resources.target].compact |
711 test.dependencies.concat test.compile.dependencies |
712 # Dependency on compiled code, its dependencies and resources. |
713 test.with [project.compile.target, project.resources.target].compact |
714 test.with project.compile.dependencies |
715 # Picking up the test frameworks adds further dependencies. |
716 test.framework |
717 |
718 project.build test unless test.options[:integration] || Buildr.options.test == :only |
719 |
720 project.clean do |
721 rm_rf test.compile.target.to_s if test.compile.target |
722 rm_rf test.report_to.to_s |
723 end |
724 end |
725 |
726 |
727 # :call-seq: |
728 # test(*prereqs) => TestTask |
729 # test(*prereqs) { |task| .. } => TestTask |
730 # |
731 # Returns the test task. The test task controls the entire test lifecycle. |
732 # |
733 # You can use the test task in three ways. You can access and configure specific |
734 # test tasks, e.g. enhance the compile task by calling test.compile, setup for |
735 # the tests by enhancing test.setup and so forth. |
736 # |
737 # You can use convenient methods that handle the most common settings. For example, |
738 # add dependencies using test.with, or include only specific tests using test.include. |
739 # |
740 # You can also enhance this task directly. This method accepts a list of arguments |
741 # that are used as prerequisites and an optional block that will be executed by the |
742 # test task. |
743 # |
744 # This task compiles the project and the tests (in that order) before running any tests. |
745 # It execute the setup task, runs all the tests, any enhancements, and ends with the |
746 # teardown tasks. |
747 def test(*prereqs, &block) |
748 task('test').enhance prereqs, &block |
749 end |
750 |
751 # :call-seq: |
752 # integration { |task| .... } |
753 # integration => IntegrationTestTask |
754 # |
755 # Use this method to return the integration tests task, or enhance it with a block to execute. |
756 # |
757 # There is one integration tests task you can execute directly, or as a result of running the package |
758 # task (or tasks that depend on it, like install and upload). It contains all the tests marked with |
759 # :integration=>true, all other tests are considered unit tests and run by the test task before packaging. |
760 # So essentially: build=>test=>packaging=>integration=>install/upload. |
761 # |
762 # You add new tests from projects that define integration tests using the regular test task, |
763 # but with the following addition: |
764 # test.using :integration |
765 # |
766 # Use this method to enhance the setup and teardown tasks that are executed before (and after) all |
767 # integration tests are run, for example, to start a Web server or create a database. |
768 def integration(*deps, &block) |
769 Rake::Task['rake:integration'].enhance deps, &block |
770 end |
771 |
772 end |
773 |
774 |
775 # :call-seq: |
776 # integration { |task| .... } |
777 # integration => IntegrationTestTask |
778 # |
779 # Use this method to return the integration tests task. |
780 def integration(*deps, &block) |
781 Rake::Task['rake:integration'].enhance deps, &block |
782 end |
783 |
784 class Options |
785 |
786 # Runs tests after the build when true (default). This forces tests to execute |
787 # after the build, including when running build related tasks like install, upload and release. |
788 # |
789 # Set to false to not run any tests. Set to :all to run all tests, ignoring failures. |
790 # |
791 # This option is set from the environment variable 'test', so you can also do: |
792 |
793 # Returns the test option (environment variable TEST). Possible values are: |
794 # * :false -- Do not run any tests (also accepts 'no' and 'skip'). |
795 # * :true -- Run all tests, stop on failure (default if not set). |
796 # * :all -- Run all tests, ignore failures. |
797 def test |
798 case value = ENV['TEST'] || ENV['test'] |
799 when /^(no|off|false|skip)$/i |
800 false |
801 when /^all$/i |
802 :all |
803 when /^only$/i |
804 :only |
805 when /^(yes|on|true)$/i, nil |
806 true |
807 else |
808 warn "Expecting the environment variable test to be 'no' or 'all', not sure what to do with #{value}, so I'm just going to run all the tests and stop at failure." |
809 true |
810 end |
811 end |
812 |
813 # Sets the test option (environment variable TEST). Possible values are true, false or :all. |
814 # |
815 # You can also set this from the environment variable, e.g.: |
816 # |
817 # buildr # With tests |
818 # buildr test=no # Without tests |
819 # buildr test=all # Ignore failures |
820 # set TEST=no |
821 # buildr # Without tests |
822 def test=(flag) |
823 ENV['test'] = nil |
824 ENV['TEST'] = flag.to_s |
825 end |
826 |
827 end |
828 |
829 Buildr.help << <<-HELP |
830 To run a full build without running any tests: |
831 buildr test=no |
832 To run specific test: |
833 buildr test:MyTest |
834 To run integration tests: |
835 buildr integration |
836 HELP |
837 |
838 end |
839 |
840 |
841 class Buildr::Project |
842 include Buildr::Test |
843 end |
Generated on 2011-07-06 23:35:37 -0700 with rcov 0.9.8