/
TestCase.php
160 lines (136 loc) 路 3.54 KB
/
TestCase.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
<?php
/**
* This file is part of the Nette Tester.
* Copyright (c) 2009 David Grudl (http://davidgrudl.com)
*/
namespace Tester;
/**
* Single test case.
*
* @author David Grudl
*/
class TestCase
{
/** @internal */
const LIST_METHODS = 'nette-tester-list-methods',
METHOD_PATTERN = '#^test[A-Z0-9_]#';
/**
* Runs the test case.
* @return void
*/
public function run($method = NULL)
{
if ($method === NULL && isset($_SERVER['argv'][1])) {
if ($_SERVER['argv'][1] === self::LIST_METHODS) {
echo json_encode(preg_grep(self::METHOD_PATTERN, get_class_methods($this)));
return;
}
$method = $_SERVER['argv'][1];
}
$methods = preg_grep(self::METHOD_PATTERN, $method ? array($method) : get_class_methods($this));
foreach ($methods as $method) {
$this->runMethod($method);
}
}
/**
* Runs the test method.
* @return void
*/
private function runMethod($method)
{
$method = new \ReflectionMethod($this, $method);
if (!$method->isPublic()) {
throw new TestCaseException("Method {$method->getName()} is not public. Make it public or rename it.");
}
$data = array();
$info = Helpers::parseDocComment($method->getDocComment()) + array('dataprovider' => NULL, 'throws' => NULL);
if ($info['throws'] === '') {
throw new TestCaseException("Missing class name in @throws annotation for {$method->getName()}().");
} elseif (is_array($info['throws'])) {
throw new TestCaseException("Annotation @throws for {$method->getName()}() can be specified only once.");
} else {
$throws = preg_split('#\s+#', $info['throws'], 2) + array(NULL, NULL);
}
foreach ((array) $info['dataprovider'] as $provider) {
$res = $this->getData($provider);
if (!is_array($res)) {
throw new TestCaseException("Data provider $provider() doesn't return array.");
}
$data = array_merge($data, $res);
}
if (!$info['dataprovider']) {
if ($method->getNumberOfRequiredParameters()) {
throw new TestCaseException("Method {$method->getName()}() has arguments, but @dataProvider is missing.");
}
$data[] = array();
}
foreach ($data as $args) {
try {
if ($info['throws']) {
$tmp = $this;
$e = Assert::error(function() use ($tmp, $method, $args) {
$tmp->runTest($method->getName(), $args);
}, $throws[0], $throws[1]);
if ($e instanceof AssertException) {
throw $e;
}
} else {
$this->runTest($method->getName(), $args);
}
} catch (AssertException $e) {
$e->message .= " in {$method->getName()}" . (substr(Dumper::toLine($args), 5));
throw $e;
}
}
}
/**
* Runs the single test.
* @return void
*/
public function runTest($name, array $args = array())
{
$this->setUp();
try {
call_user_func_array(array($this, $name), $args);
} catch (\Exception $e) {
}
try {
$this->tearDown();
} catch (\Exception $tearDownEx) {
throw isset($e) ? $e : $tearDownEx;
}
if (isset($e)) {
throw $e;
}
}
/**
* @return array
*/
protected function getData($provider)
{
if (strpos($provider, '.')) {
list($file, $query) = preg_split('#\s*,?\s+#', "$provider ", 2);
$rc = new \ReflectionClass($this);
return DataProvider::load(dirname($rc->getFileName()) . DIRECTORY_SEPARATOR . $file, $query);
} else {
return $this->$provider();
}
}
/**
* This method is called before a test is executed.
* @return void
*/
protected function setUp()
{
}
/**
* This method is called after a test is executed.
* @return void
*/
protected function tearDown()
{
}
}
class TestCaseException extends \Exception
{
}