source: classes/phing/tasks/ext/phpunit/PHPUnitTask.php @ e738d93b

Last change on this file since e738d93b was e738d93b, checked in by Michiel Rook <mrook@…>, 4 years ago

Refs #608 - also remember last incomplete / skipped messages (patch by Tim Gerundt)

  • Property mode set to 100644
File size: 10.4 KB
Line 
1<?php
2/**
3 * $Id$
4 *
5 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
6 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
7 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
8 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
9 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
10 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
12 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
13 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
15 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16 *
17 * This software consists of voluntary contributions made by many individuals
18 * and is licensed under the LGPL. For more information please see
19 * <http://phing.info>.
20 */
21
22require_once 'phing/Task.php';
23require_once 'phing/system/io/PhingFile.php';
24require_once 'phing/system/io/Writer.php';
25require_once 'phing/util/LogWriter.php';
26
27/**
28 * Runs PHPUnit tests.
29 *
30 * @author Michiel Rook <michiel.rook@gmail.com>
31 * @version $Id$
32 * @package phing.tasks.ext.phpunit
33 * @see BatchTest
34 * @since 2.1.0
35 */
36class PHPUnitTask extends Task
37{
38    private $batchtests = array();
39    private $formatters = array();
40    private $bootstrap = "";
41    private $haltonerror = false;
42    private $haltonfailure = false;
43    private $haltonincomplete = false;
44    private $haltonskipped = false;
45    private $errorproperty;
46    private $failureproperty;
47    private $incompleteproperty;
48    private $skippedproperty;
49    private $printsummary = false;
50    private $testfailed = false;
51    private $testfailuremessage = "";
52    private $codecoverage = false;
53    private $groups = array();
54    private $excludeGroups = array();
55    private $usecustomerrorhandler = true;
56
57    /**
58     * Initialize Task.
59     * This method includes any necessary PHPUnit2 libraries and triggers
60     * appropriate error if they cannot be found.  This is not done in header
61     * because we may want this class to be loaded w/o triggering an error.
62     */
63    public function init() {
64        if (version_compare(PHP_VERSION, '5.0.3') < 0)
65        {
66            throw new BuildException("PHPUnitTask requires PHP version >= 5.0.3", $this->getLocation());
67        }
68       
69        /**
70         * Determine PHPUnit version number
71         */
72        @include_once 'PHPUnit/Runner/Version.php';
73
74        $version = PHPUnit_Runner_Version::id();
75
76        if (version_compare($version, '3.2.0') < 0)
77        {
78            throw new BuildException("PHPUnitTask requires PHPUnit version >= 3.2.0", $this->getLocation());
79        }
80           
81        /**
82         * Other dependencies that should only be loaded when class is actually used.
83         */
84        require_once 'phing/tasks/ext/phpunit/PHPUnitTestRunner.php';
85        require_once 'phing/tasks/ext/phpunit/BatchTest.php';
86        require_once 'phing/tasks/ext/phpunit/FormatterElement.php';
87
88        /**
89         * point PHPUnit_MAIN_METHOD define to non-existing method
90         */
91        if (!defined('PHPUnit_MAIN_METHOD'))
92        {
93            define('PHPUnit_MAIN_METHOD', 'PHPUnitTask::undefined');
94        }
95       
96        /**
97         * Add some defaults to the PHPUnit filter
98         */
99        $pwd = dirname(__FILE__);
100        $path = realpath($pwd . '/../../../');
101       
102        if (version_compare($version, '3.5.0') >= 0) {
103            PHP_CodeCoverage_Filter::getInstance()->addDirectoryToBlacklist($path);
104        } else {
105            require_once 'PHPUnit/Framework.php';
106            require_once 'PHPUnit/Util/Filter.php';
107           
108            PHPUnit_Util_Filter::addDirectoryToFilter($path);
109        }
110    }
111   
112    /**
113     * Sets the name of a bootstrap file that is run before
114     * executing the tests
115     *
116     * @param string $bootstrap the name of the bootstrap file
117     */
118    public function setBootstrap($bootstrap)
119    {
120        $this->bootstrap = $bootstrap;
121    }
122   
123    public function setErrorproperty($value)
124    {
125        $this->errorproperty = $value;
126    }
127   
128    public function setFailureproperty($value)
129    {
130        $this->failureproperty = $value;
131    }
132   
133    public function setIncompleteproperty($value)
134    {
135        $this->incompleteproperty = $value;
136    }
137   
138    public function setSkippedproperty($value)
139    {
140        $this->skippedproperty = $value;
141    }
142   
143    public function setHaltonerror($value)
144    {
145        $this->haltonerror = $value;
146    }
147
148    public function setHaltonfailure($value)
149    {
150        $this->haltonfailure = $value;
151    }
152   
153    public function getHaltonfailure()
154    {
155        return $this->haltonfailure;
156    }
157
158    public function setHaltonincomplete($value)
159    {
160        $this->haltonincomplete = $value;
161    }
162   
163    public function getHaltonincomplete()
164    {
165        return $this->haltonincomplete;
166    }
167
168    public function setHaltonskipped($value)
169    {
170        $this->haltonskipped = $value;
171    }
172   
173    public function getHaltonskipped()
174    {
175        return $this->haltonskipped;
176    }
177
178    public function setPrintsummary($printsummary)
179    {
180        $this->printsummary = $printsummary;
181    }
182   
183    public function setCodecoverage($codecoverage)
184    {
185        $this->codecoverage = $codecoverage;
186    }
187
188    public function setUseCustomErrorHandler($usecustomerrorhandler)
189    {
190        $this->usecustomerrorhandler = $usecustomerrorhandler;
191    }
192
193    public function setGroups($groups)
194    {
195        $token = ' ,;';
196        $this->groups = array();
197        $tok = strtok($groups, $token);
198        while ($tok !== false) {
199            $this->groups[] = $tok;
200            $tok = strtok($token);
201        }
202    }
203
204    public function setExcludeGroups($excludeGroups)
205    {
206        $token = ' ,;';
207        $this->excludeGroups = array();
208        $tok = strtok($excludeGroups, $token);
209        while ($tok !== false) {
210            $this->excludeGroups[] = $tok;
211            $tok = strtok($token);
212        }
213    }
214
215    /**
216     * Add a new formatter to all tests of this task.
217     *
218     * @param FormatterElement formatter element
219     */
220    public function addFormatter(FormatterElement $fe)
221    {
222        $fe->setParent($this);
223        $this->formatters[] = $fe;
224    }
225
226    /**
227     * The main entry point
228     *
229     * @throws BuildException
230     */
231    public function main()
232    {
233        if ($this->codecoverage && !extension_loaded('xdebug'))
234        {
235            throw new Exception("PHPUnitTask depends on Xdebug being installed to gather code coverage information.");
236        }
237
238        if ($this->printsummary)
239        {
240            $fe = new FormatterElement();
241            $fe->setParent($this);
242            $fe->setType("summary");
243            $fe->setUseFile(false);
244            $this->formatters[] = $fe;
245        }
246       
247        if ($this->bootstrap)
248        {
249            require_once $this->bootstrap;
250        }
251       
252        foreach ($this->formatters as $fe)
253        {
254            $formatter = $fe->getFormatter();
255
256            if ($fe->getUseFile())
257            {
258                $destFile = new PhingFile($fe->getToDir(), $fe->getOutfile());
259               
260                $writer = new FileWriter($destFile->getAbsolutePath());
261
262                $formatter->setOutput($writer);
263            }
264            else
265            {
266                $formatter->setOutput($this->getDefaultOutput());
267            }
268
269            $formatter->startTestRun();
270        }
271       
272        foreach ($this->batchtests as $batchtest)
273        {
274            $this->execute($batchtest->getTestSuite());
275        }           
276       
277        foreach ($this->formatters as $fe)
278        {
279            $formatter = $fe->getFormatter();
280            $formatter->endTestRun();
281        }
282       
283        if ($this->testfailed)
284        {
285            throw new BuildException($this->testfailuremessage);
286        }
287    }
288
289    /**
290     * @throws BuildException
291     */
292    protected function execute($suite)
293    {
294        $runner = new PHPUnitTestRunner($this->project, $this->groups, $this->excludeGroups);
295       
296        $runner->setCodecoverage($this->codecoverage);
297        $runner->setUseCustomErrorHandler($this->usecustomerrorhandler);
298
299        foreach ($this->formatters as $fe)
300        {
301            $formatter = $fe->getFormatter();
302
303            $runner->addFormatter($formatter);     
304        }
305       
306        $runner->run($suite);
307
308        $retcode = $runner->getRetCode();
309       
310        if ($retcode == PHPUnitTestRunner::ERRORS) {
311            if ($this->errorproperty) {
312                $this->project->setNewProperty($this->errorproperty, true);
313            }
314            if ($this->haltonerror) {
315                $this->testfailed = true;
316                $this->testfailuremessage = $runner->getLastErrorMessage();
317            }
318        } elseif ($retcode == PHPUnitTestRunner::FAILURES) {
319            if ($this->failureproperty) {
320                $this->project->setNewProperty($this->failureproperty, true);
321            }
322           
323            if ($this->haltonfailure) {
324                $this->testfailed = true;
325                $this->testfailuremessage = $runner->getLastFailureMessage();
326            }
327        } elseif ($retcode == PHPUnitTestRunner::INCOMPLETES) {
328            if ($this->incompleteproperty) {
329                $this->project->setNewProperty($this->incompleteproperty, true);
330            }
331           
332            if ($this->haltonincomplete) {
333                $this->testfailed = true;
334                $this->testfailuremessage = $runner->getLastIncompleteMessage();
335            }
336        } elseif ($retcode == PHPUnitTestRunner::SKIPPED) {
337            if ($this->skippedproperty) {
338                $this->project->setNewProperty($this->skippedproperty, true);
339            }
340           
341            if ($this->haltonskipped) {
342                $this->testfailed = true;
343                $this->testfailuremessage = $runner->getLastSkippedMessage();
344            }
345        }
346    }
347
348    protected function getDefaultOutput()
349    {
350        return new LogWriter($this);
351    }
352
353    /**
354     * Adds a set of tests based on pattern matching.
355     *
356     * @return BatchTest a new instance of a batch test.
357     */
358    public function createBatchTest()
359    {
360        $batchtest = new BatchTest($this->getProject());
361
362        $this->batchtests[] = $batchtest;
363
364        return $batchtest;
365    }
366}
367
Note: See TracBrowser for help on using the repository browser.