mas01mj@732
|
1 package asunit.framework {
|
mas01mj@732
|
2 import flash.display.DisplayObject;
|
mas01mj@732
|
3 import flash.display.DisplayObjectContainer;
|
mas01mj@732
|
4 import flash.errors.IllegalOperationError;
|
mas01mj@732
|
5 import flash.events.Event;
|
mas01mj@732
|
6 import flash.utils.describeType;
|
mas01mj@732
|
7 import flash.utils.getDefinitionByName;
|
mas01mj@732
|
8 import flash.utils.setTimeout;
|
mas01mj@732
|
9
|
mas01mj@732
|
10 import asunit.errors.AssertionFailedError;
|
mas01mj@732
|
11 import asunit.util.ArrayIterator;
|
mas01mj@732
|
12 import asunit.util.Iterator;
|
mas01mj@732
|
13
|
mas01mj@732
|
14 /**
|
mas01mj@732
|
15 * A test case defines the fixture to run multiple tests. To define a test case<br>
|
mas01mj@732
|
16 * 1) implement a subclass of TestCase<br>
|
mas01mj@732
|
17 * 2) define instance variables that store the state of the fixture<br>
|
mas01mj@732
|
18 * 3) initialize the fixture state by overriding <code>setUp</code><br>
|
mas01mj@732
|
19 * 4) clean-up after a test by overriding <code>tearDown</code>.<br>
|
mas01mj@732
|
20 * Each test runs in its own fixture so there
|
mas01mj@732
|
21 * can be no side effects among test runs.
|
mas01mj@732
|
22 * Here is an example:
|
mas01mj@732
|
23 * <listing>
|
mas01mj@732
|
24 * public class MathTest extends TestCase {
|
mas01mj@732
|
25 * private var value1:Number;
|
mas01mj@732
|
26 * private var value2:Number;
|
mas01mj@732
|
27 *
|
mas01mj@732
|
28 * public function MathTest(methodName:String=null) {
|
mas01mj@732
|
29 * super(methodName);
|
mas01mj@732
|
30 * }
|
mas01mj@732
|
31 *
|
mas01mj@732
|
32 * override protected function setUp():void {
|
mas01mj@732
|
33 * super.setUp();
|
mas01mj@732
|
34 * value1 = 2;
|
mas01mj@732
|
35 * value2 = 3;
|
mas01mj@732
|
36 * }
|
mas01mj@732
|
37 * }
|
mas01mj@732
|
38 * </listing>
|
mas01mj@732
|
39 *
|
mas01mj@732
|
40 * For each test implement a method which interacts
|
mas01mj@732
|
41 * with the fixture. Verify the expected results with assertions specified
|
mas01mj@732
|
42 * by calling <code>assertTrue</code> with a boolean, or <code>assertEquals</code>
|
mas01mj@732
|
43 * with two primitive values that should match.
|
mas01mj@732
|
44 * <listing>
|
mas01mj@732
|
45 * public function testAdd():void {
|
mas01mj@732
|
46 * var result:Number = value1 + value2;
|
mas01mj@732
|
47 * assertEquals(5, result);
|
mas01mj@732
|
48 * }
|
mas01mj@732
|
49 * </listing>
|
mas01mj@732
|
50 *
|
mas01mj@732
|
51 * There are three common types of test cases:
|
mas01mj@732
|
52 *
|
mas01mj@732
|
53 * <ol>
|
mas01mj@732
|
54 * <li>Simple unit test</li>
|
mas01mj@732
|
55 * <li>Visual integration test</li>
|
mas01mj@732
|
56 * <li>Asynchronous test</li>
|
mas01mj@732
|
57 * </ol>
|
mas01mj@732
|
58 *
|
mas01mj@732
|
59 * @includeExample MathUtilTest.as
|
mas01mj@732
|
60 * @includeExample ComponentTestIntroduction.as
|
mas01mj@732
|
61 * @includeExample ComponentUnderTest.as
|
mas01mj@732
|
62 * @includeExample ComponentTestExample.as
|
mas01mj@732
|
63 * @includeExample AsynchronousTestMethodExample.as
|
mas01mj@732
|
64 */
|
mas01mj@732
|
65 public class TestCase extends Assert implements Test {
|
mas01mj@732
|
66 protected static const PRE_SET_UP:int = 0;
|
mas01mj@732
|
67 protected static const SET_UP:int = 1;
|
mas01mj@732
|
68 protected static const RUN_METHOD:int = 2;
|
mas01mj@732
|
69 protected static const TEAR_DOWN:int = 3;
|
mas01mj@732
|
70 protected static const DEFAULT_TIMEOUT:int = 1000;
|
mas01mj@732
|
71
|
mas01mj@732
|
72 protected var context:DisplayObjectContainer;
|
mas01mj@732
|
73 protected var fName:String;
|
mas01mj@732
|
74 protected var isComplete:Boolean;
|
mas01mj@732
|
75 protected var result:TestListener;
|
mas01mj@732
|
76 protected var testMethods:Array;
|
mas01mj@732
|
77
|
mas01mj@732
|
78 private var asyncQueue:Array;
|
mas01mj@732
|
79 private var currentMethod:String;
|
mas01mj@732
|
80 private var currentState:int;
|
mas01mj@732
|
81 private var layoutManager:Object;
|
mas01mj@732
|
82 private var methodIterator:Iterator;
|
mas01mj@732
|
83 private var runSingle:Boolean;
|
mas01mj@732
|
84
|
mas01mj@732
|
85 /**
|
mas01mj@732
|
86 * Constructs a test case with the given name.
|
mas01mj@732
|
87 *
|
mas01mj@732
|
88 * Be sure to implement the constructor in your own TestCase base classes.
|
mas01mj@732
|
89 *
|
mas01mj@732
|
90 * Using the optional <code>testMethod</code> constructor parameter is how we
|
mas01mj@732
|
91 * create and run a single test case and test method.
|
mas01mj@732
|
92 */
|
mas01mj@732
|
93 public function TestCase(testMethod:String = null) {
|
mas01mj@732
|
94 var description:XML = describeType(this);
|
mas01mj@732
|
95 var className:Object = description.@name;
|
mas01mj@732
|
96 var methods:XMLList = description..method.((@name+"").match("^test"));
|
mas01mj@732
|
97 if(testMethod != null) {
|
mas01mj@732
|
98 testMethods = testMethod.split(", ").join(",").split(",");
|
mas01mj@732
|
99 if(testMethods.length == 1) {
|
mas01mj@732
|
100 runSingle = true;
|
mas01mj@732
|
101 }
|
mas01mj@732
|
102 } else {
|
mas01mj@732
|
103 setTestMethods(methods);
|
mas01mj@732
|
104 }
|
mas01mj@732
|
105 setName(className.toString());
|
mas01mj@732
|
106 resolveLayoutManager();
|
mas01mj@732
|
107 asyncQueue = [];
|
mas01mj@732
|
108 }
|
mas01mj@732
|
109
|
mas01mj@732
|
110 private function resolveLayoutManager():void {
|
mas01mj@732
|
111 // Avoid creating import dependencies on flex framework
|
mas01mj@732
|
112 // If you have the framework.swc in your classpath,
|
mas01mj@732
|
113 // the layout manager will be found, if not, a mcok
|
mas01mj@732
|
114 // will be used.
|
mas01mj@732
|
115 try {
|
mas01mj@732
|
116 var manager:Class = getDefinitionByName("mx.managers.LayoutManager") as Class;
|
mas01mj@732
|
117 layoutManager = manager["getInstance"]();
|
mas01mj@732
|
118 if(!layoutManager.hasOwnProperty("resetAll")) {
|
mas01mj@732
|
119 throw new Error("TestCase :: mx.managers.LayoutManager missing resetAll method");
|
mas01mj@732
|
120 }
|
mas01mj@732
|
121 }
|
mas01mj@732
|
122 catch(e:Error) {
|
mas01mj@732
|
123 layoutManager = new Object();
|
mas01mj@732
|
124 layoutManager.resetAll = function():void {
|
mas01mj@732
|
125 };
|
mas01mj@732
|
126 }
|
mas01mj@732
|
127 }
|
mas01mj@732
|
128
|
mas01mj@732
|
129 /**
|
mas01mj@732
|
130 * Sets the name of a TestCase
|
mas01mj@732
|
131 * @param name The name to set
|
mas01mj@732
|
132 */
|
mas01mj@732
|
133 public function setName(name:String):void {
|
mas01mj@732
|
134 fName = name;
|
mas01mj@732
|
135 }
|
mas01mj@732
|
136
|
mas01mj@732
|
137 protected function setTestMethods(methodNodes:XMLList):void {
|
mas01mj@732
|
138 testMethods = new Array();
|
mas01mj@732
|
139 var methodNames:Object = methodNodes.@name;
|
mas01mj@732
|
140 var name:String;
|
mas01mj@732
|
141 for each(var item:Object in methodNames) {
|
mas01mj@732
|
142 name = item.toString();
|
mas01mj@732
|
143 testMethods.push(name);
|
mas01mj@732
|
144 }
|
mas01mj@732
|
145 }
|
mas01mj@732
|
146
|
mas01mj@732
|
147 public function getTestMethods():Array {
|
mas01mj@732
|
148 return testMethods;
|
mas01mj@732
|
149 }
|
mas01mj@732
|
150
|
mas01mj@732
|
151 /**
|
mas01mj@732
|
152 * Counts the number of test cases executed by run(TestResult result).
|
mas01mj@732
|
153 */
|
mas01mj@732
|
154 public function countTestCases():int {
|
mas01mj@732
|
155 return testMethods.length;
|
mas01mj@732
|
156 }
|
mas01mj@732
|
157
|
mas01mj@732
|
158 /**
|
mas01mj@732
|
159 * Creates a default TestResult object
|
mas01mj@732
|
160 *
|
mas01mj@732
|
161 * @see TestResult
|
mas01mj@732
|
162 */
|
mas01mj@732
|
163 protected function createResult():TestResult {
|
mas01mj@732
|
164 return new TestResult();
|
mas01mj@732
|
165 }
|
mas01mj@732
|
166
|
mas01mj@732
|
167 /**
|
mas01mj@732
|
168 * A convenience method to run this test, collecting the results with
|
mas01mj@732
|
169 * either the TestResult provided or a default, new TestResult object.
|
mas01mj@732
|
170 * Expects either:
|
mas01mj@732
|
171 * run():void // will return the newly created TestResult
|
mas01mj@732
|
172 * run(result:TestResult):TestResult // will use the TestResult
|
mas01mj@732
|
173 * that was passed in.
|
mas01mj@732
|
174 *
|
mas01mj@732
|
175 * @see TestResult
|
mas01mj@732
|
176 */
|
mas01mj@732
|
177 public function run():void {
|
mas01mj@732
|
178 getResult().run(this);
|
mas01mj@732
|
179 }
|
mas01mj@732
|
180
|
mas01mj@732
|
181 public function setResult(result:TestListener):void {
|
mas01mj@732
|
182 this.result = result;
|
mas01mj@732
|
183 }
|
mas01mj@732
|
184
|
mas01mj@732
|
185 internal function getResult():TestListener {
|
mas01mj@732
|
186 return (result == null) ? createResult() : result;
|
mas01mj@732
|
187 }
|
mas01mj@732
|
188
|
mas01mj@732
|
189 /**
|
mas01mj@732
|
190 * Runs the bare test sequence.
|
mas01mj@732
|
191 * @throws Error if any exception is thrown
|
mas01mj@732
|
192 */
|
mas01mj@732
|
193 public function runBare():void {
|
mas01mj@732
|
194 if(isComplete) {
|
mas01mj@732
|
195 return;
|
mas01mj@732
|
196 }
|
mas01mj@732
|
197 var name:String;
|
mas01mj@732
|
198 var itr:Iterator = getMethodIterator();
|
mas01mj@732
|
199 if(itr.hasNext()) {
|
mas01mj@732
|
200 name = String(itr.next());
|
mas01mj@732
|
201 currentState = PRE_SET_UP;
|
mas01mj@732
|
202 runMethod(name);
|
mas01mj@732
|
203 }
|
mas01mj@732
|
204 else {
|
mas01mj@732
|
205 cleanUp();
|
mas01mj@732
|
206 getResult().endTest(this);
|
mas01mj@732
|
207 isComplete = true;
|
mas01mj@732
|
208 dispatchEvent(new Event(Event.COMPLETE));
|
mas01mj@732
|
209 }
|
mas01mj@732
|
210 }
|
mas01mj@732
|
211
|
mas01mj@732
|
212 private function getMethodIterator():Iterator {
|
mas01mj@732
|
213 if(methodIterator == null) {
|
mas01mj@732
|
214 methodIterator = new ArrayIterator(testMethods);
|
mas01mj@732
|
215 }
|
mas01mj@732
|
216 return methodIterator;
|
mas01mj@732
|
217 }
|
mas01mj@732
|
218
|
mas01mj@732
|
219 /**
|
mas01mj@732
|
220 * Override this method in Asynchronous test cases
|
mas01mj@732
|
221 * or any other time you want to perform additional
|
mas01mj@732
|
222 * member cleanup after all test methods have run
|
mas01mj@732
|
223 **/
|
mas01mj@732
|
224 protected function cleanUp():void {
|
mas01mj@732
|
225 }
|
mas01mj@732
|
226
|
mas01mj@732
|
227 private function runMethod(methodName:String):void {
|
mas01mj@732
|
228 try {
|
mas01mj@732
|
229 if(currentState == PRE_SET_UP) {
|
mas01mj@732
|
230 currentState = SET_UP;
|
mas01mj@732
|
231 getResult().startTestMethod(this, methodName);
|
mas01mj@732
|
232 setUp(); // setUp may be async and change the state of methodIsAsynchronous
|
mas01mj@732
|
233 }
|
mas01mj@732
|
234 currentMethod = methodName;
|
mas01mj@732
|
235 if(!waitForAsync()) {
|
mas01mj@732
|
236 currentState = RUN_METHOD;
|
mas01mj@732
|
237 this[methodName]();
|
mas01mj@732
|
238 }
|
mas01mj@732
|
239 }
|
mas01mj@732
|
240 catch(assertionFailedError:AssertionFailedError) {
|
mas01mj@732
|
241 getResult().addFailure(this, assertionFailedError);
|
mas01mj@732
|
242 }
|
mas01mj@732
|
243 catch(unknownError:Error) {
|
mas01mj@732
|
244 getResult().addError(this, unknownError);
|
mas01mj@732
|
245 }
|
mas01mj@732
|
246 finally {
|
mas01mj@732
|
247 if(!waitForAsync()) {
|
mas01mj@732
|
248 runTearDown();
|
mas01mj@732
|
249 }
|
mas01mj@732
|
250 }
|
mas01mj@732
|
251 }
|
mas01mj@732
|
252
|
mas01mj@732
|
253 /**
|
mas01mj@732
|
254 * Sets up the fixture, for example, instantiate a mock object.
|
mas01mj@732
|
255 * This method is called before each test is executed.
|
mas01mj@732
|
256 * throws Exception on error.
|
mas01mj@732
|
257 *
|
mas01mj@732
|
258 * @example This method is usually overridden in your concrete test cases:
|
mas01mj@732
|
259 * <listing>
|
mas01mj@732
|
260 * private var instance:MyInstance;
|
mas01mj@732
|
261 *
|
mas01mj@732
|
262 * override protected function setUp():void {
|
mas01mj@732
|
263 * super.setUp();
|
mas01mj@732
|
264 * instance = new MyInstance();
|
mas01mj@732
|
265 * addChild(instance);
|
mas01mj@732
|
266 * }
|
mas01mj@732
|
267 * </listing>
|
mas01mj@732
|
268 */
|
mas01mj@732
|
269 protected function setUp():void {
|
mas01mj@732
|
270 }
|
mas01mj@732
|
271 /**
|
mas01mj@732
|
272 * Tears down the fixture, for example, delete mock object.
|
mas01mj@732
|
273 *
|
mas01mj@732
|
274 * This method is called after a test is executed - even if the test method
|
mas01mj@732
|
275 * throws an exception or fails.
|
mas01mj@732
|
276 *
|
mas01mj@732
|
277 * Even though the base class <code>TestCase</code> doesn't do anything on <code>tearDown</code>,
|
mas01mj@732
|
278 * It's a good idea to call <code>super.tearDown()</code> in your subclasses. Many projects
|
mas01mj@732
|
279 * wind up using some common fixtures which can often be extracted out a common project
|
mas01mj@732
|
280 * <code>TestCase</code>.
|
mas01mj@732
|
281 *
|
mas01mj@732
|
282 * <code>tearDown</code> is <em>not</em> called when we tell a test case to execute
|
mas01mj@732
|
283 * a single test method.
|
mas01mj@732
|
284 *
|
mas01mj@732
|
285 * @throws Error on error.
|
mas01mj@732
|
286 *
|
mas01mj@732
|
287 * @example This method is usually overridden in your concrete test cases:
|
mas01mj@732
|
288 * <listing>
|
mas01mj@732
|
289 * private var instance:MyInstance;
|
mas01mj@732
|
290 *
|
mas01mj@732
|
291 * override protected function setUp():void {
|
mas01mj@732
|
292 * super.setUp();
|
mas01mj@732
|
293 * instance = new MyInstance();
|
mas01mj@732
|
294 * addChild(instance);
|
mas01mj@732
|
295 * }
|
mas01mj@732
|
296 *
|
mas01mj@732
|
297 * override protected function tearDown():void {
|
mas01mj@732
|
298 * super.tearDown();
|
mas01mj@732
|
299 * removeChild(instance);
|
mas01mj@732
|
300 * }
|
mas01mj@732
|
301 * </listing>
|
mas01mj@732
|
302 *
|
mas01mj@732
|
303 */
|
mas01mj@732
|
304 protected function tearDown():void {
|
mas01mj@732
|
305 }
|
mas01mj@732
|
306
|
mas01mj@732
|
307 /**
|
mas01mj@732
|
308 * Returns a string representation of the test case
|
mas01mj@732
|
309 */
|
mas01mj@732
|
310 override public function toString():String {
|
mas01mj@732
|
311 if(getCurrentMethod()) {
|
mas01mj@732
|
312 return getName() + "." + getCurrentMethod() + "()";
|
mas01mj@732
|
313 }
|
mas01mj@732
|
314 else {
|
mas01mj@732
|
315 return getName();
|
mas01mj@732
|
316 }
|
mas01mj@732
|
317 }
|
mas01mj@732
|
318 /**
|
mas01mj@732
|
319 * Gets the name of a TestCase
|
mas01mj@732
|
320 * @return returns a String
|
mas01mj@732
|
321 */
|
mas01mj@732
|
322 public function getName():String {
|
mas01mj@732
|
323 return fName;
|
mas01mj@732
|
324 }
|
mas01mj@732
|
325
|
mas01mj@732
|
326 public function getCurrentMethod():String {
|
mas01mj@732
|
327 return currentMethod;
|
mas01mj@732
|
328 }
|
mas01mj@732
|
329
|
mas01mj@732
|
330 public function getIsComplete():Boolean {
|
mas01mj@732
|
331 return isComplete;
|
mas01mj@732
|
332 }
|
mas01mj@732
|
333
|
mas01mj@732
|
334 public function setContext(context:DisplayObjectContainer):void {
|
mas01mj@732
|
335 this.context = context;
|
mas01mj@732
|
336 }
|
mas01mj@732
|
337
|
mas01mj@732
|
338 /**
|
mas01mj@732
|
339 * Returns the visual <code>DisplayObjectContainer</code> that will be used by
|
mas01mj@732
|
340 * <code>addChild</code> and <code>removeChild</code> helper methods.
|
mas01mj@732
|
341 **/
|
mas01mj@732
|
342 public function getContext():DisplayObjectContainer {
|
mas01mj@732
|
343 return context;
|
mas01mj@732
|
344 }
|
mas01mj@732
|
345
|
mas01mj@732
|
346 /**
|
mas01mj@732
|
347 * Called from within <code>setUp</code> or the body of any test method.
|
mas01mj@732
|
348 *
|
mas01mj@732
|
349 * Any call to <code>addAsync</code>, will prevent test execution from continuing
|
mas01mj@732
|
350 * until the <code>duration</code> (in milliseconds) is exceeded, or the function returned by <code>addAsync</code>
|
mas01mj@732
|
351 * is called. <code>addAsync</code> can be called any number of times within a particular
|
mas01mj@732
|
352 * test method, and will block execution until each handler has returned.
|
mas01mj@732
|
353 *
|
mas01mj@732
|
354 * Following is an example of how to use the <code>addAsync</code> feature:
|
mas01mj@732
|
355 * <listing>
|
mas01mj@732
|
356 * public function testDispatcher():void {
|
mas01mj@732
|
357 * var dispatcher:IEventDispatcher = new EventDispatcher();
|
mas01mj@732
|
358 * // Subscribe to an event by sending the return value of addAsync:
|
mas01mj@732
|
359 * dispatcher.addEventListener(Event.COMPLETE, addAsync(function(event:Event):void {
|
mas01mj@732
|
360 * // Make assertions *inside* your async handler:
|
mas01mj@732
|
361 * assertEquals(34, dispatcher.value);
|
mas01mj@732
|
362 * }));
|
mas01mj@732
|
363 * }
|
mas01mj@732
|
364 * </listing>
|
mas01mj@732
|
365 *
|
mas01mj@732
|
366 * If you just want to verify that a particular event is triggered, you don't
|
mas01mj@732
|
367 * need to provide a handler of your own, you can do the following:
|
mas01mj@732
|
368 * <listing>
|
mas01mj@732
|
369 * public function testDispatcher():void {
|
mas01mj@732
|
370 * var dispatcher:IEventDispatcher = new EventDispatcher();
|
mas01mj@732
|
371 * dispatcher.addEventListener(Event.COMPLETE, addAsync());
|
mas01mj@732
|
372 * }
|
mas01mj@732
|
373 * </listing>
|
mas01mj@732
|
374 *
|
mas01mj@732
|
375 * If you have a series of events that need to happen, you can generally add
|
mas01mj@732
|
376 * the async handler to the last one.
|
mas01mj@732
|
377 *
|
mas01mj@732
|
378 * The main thing to remember is that any assertions that happen outside of the
|
mas01mj@732
|
379 * initial thread of execution, must be inside of an <code>addAsync</code> block.
|
mas01mj@732
|
380 **/
|
mas01mj@732
|
381 protected function addAsync(handler:Function = null, duration:Number=DEFAULT_TIMEOUT, failureHandler:Function=null):Function {
|
mas01mj@732
|
382 if(handler == null) {
|
mas01mj@732
|
383 handler = function(args:*):* {return;};
|
mas01mj@732
|
384 }
|
mas01mj@732
|
385 var async:AsyncOperation = new AsyncOperation(this, handler, duration, failureHandler);
|
mas01mj@732
|
386 asyncQueue.push(async);
|
mas01mj@732
|
387 return async.getCallback();
|
mas01mj@732
|
388 }
|
mas01mj@732
|
389
|
mas01mj@732
|
390 internal function asyncOperationTimeout(async:AsyncOperation, duration:Number, isError:Boolean=true):void {
|
mas01mj@732
|
391 if(isError) getResult().addError(this, new IllegalOperationError("TestCase.timeout (" + duration + "ms) exceeded on an asynchronous operation."));
|
mas01mj@732
|
392 asyncOperationComplete(async);
|
mas01mj@732
|
393 }
|
mas01mj@732
|
394
|
mas01mj@732
|
395 internal function asyncOperationComplete(async:AsyncOperation):void{
|
mas01mj@732
|
396 // remove operation from queue
|
mas01mj@732
|
397 var i:int = asyncQueue.indexOf(async);
|
mas01mj@732
|
398 asyncQueue.splice(i,1);
|
mas01mj@732
|
399 // if we still need to wait, return
|
mas01mj@732
|
400 if(waitForAsync()) return;
|
mas01mj@732
|
401 if(currentState == SET_UP) {
|
mas01mj@732
|
402 runMethod(currentMethod);
|
mas01mj@732
|
403 }
|
mas01mj@732
|
404 else if(currentState == RUN_METHOD) {
|
mas01mj@732
|
405 runTearDown();
|
mas01mj@732
|
406 }
|
mas01mj@732
|
407 }
|
mas01mj@732
|
408
|
mas01mj@732
|
409 private function waitForAsync():Boolean{
|
mas01mj@732
|
410 return asyncQueue.length > 0;
|
mas01mj@732
|
411 }
|
mas01mj@732
|
412
|
mas01mj@732
|
413 protected function runTearDown():void {
|
mas01mj@732
|
414 if(currentState == TEAR_DOWN) {
|
mas01mj@732
|
415 return;
|
mas01mj@732
|
416 }
|
mas01mj@732
|
417 currentState = TEAR_DOWN;
|
mas01mj@732
|
418 if(isComplete) {
|
mas01mj@732
|
419 return;
|
mas01mj@732
|
420 }
|
mas01mj@732
|
421 if(!runSingle) {
|
mas01mj@732
|
422 getResult().endTestMethod(this, currentMethod);
|
mas01mj@732
|
423 tearDown();
|
mas01mj@732
|
424 layoutManager.resetAll();
|
mas01mj@732
|
425 }
|
mas01mj@732
|
426 setTimeout(runBare, 5);
|
mas01mj@732
|
427 }
|
mas01mj@732
|
428
|
mas01mj@732
|
429 /**
|
mas01mj@732
|
430 * Helper method for testing <code>DisplayObject</code>s.
|
mas01mj@732
|
431 *
|
mas01mj@732
|
432 * This method allows you to more easily add and manage <code>DisplayObject</code>
|
mas01mj@732
|
433 * instances in your <code>TestCase</code>.
|
mas01mj@732
|
434 *
|
mas01mj@732
|
435 * If you are using the regular <code>TestRunner</code>, you cannot add Flex classes.
|
mas01mj@732
|
436 *
|
mas01mj@732
|
437 * If you are using a <code>FlexRunner</code> base class, you can add either
|
mas01mj@732
|
438 * regular <code>DisplayObject</code>s or <code>IUIComponent</code>s.
|
mas01mj@732
|
439 *
|
mas01mj@732
|
440 * Usually, this method is called within <code>setUp</code>, and <code>removeChild</code>
|
mas01mj@732
|
441 * is called from within <code>tearDown</code>. Using these methods, ensures that added
|
mas01mj@732
|
442 * children will be subsequently removed, even when tests fail.
|
mas01mj@732
|
443 *
|
mas01mj@732
|
444 * Here is an example of the <code>addChild</code> method:
|
mas01mj@732
|
445 * <listing>
|
mas01mj@732
|
446 * private var instance:MyComponent;
|
mas01mj@732
|
447 *
|
mas01mj@732
|
448 * override protected function setUp():void {
|
mas01mj@732
|
449 * super.setUp();
|
mas01mj@732
|
450 * instance = new MyComponent();
|
mas01mj@732
|
451 * instance.addEventListener(Event.COMPLETE, addAsync());
|
mas01mj@732
|
452 * addChild(instance);
|
mas01mj@732
|
453 * }
|
mas01mj@732
|
454 *
|
mas01mj@732
|
455 * override protected function tearDown():void {
|
mas01mj@732
|
456 * super.tearDown();
|
mas01mj@732
|
457 * removeChild(instance);
|
mas01mj@732
|
458 * }
|
mas01mj@732
|
459 *
|
mas01mj@732
|
460 * public function testParam():void {
|
mas01mj@732
|
461 * assertEquals(34, instance.value);
|
mas01mj@732
|
462 * }
|
mas01mj@732
|
463 * </listing>
|
mas01mj@732
|
464 **/
|
mas01mj@732
|
465 protected function addChild(child:DisplayObject):DisplayObject {
|
mas01mj@732
|
466 return getContext().addChild(child);
|
mas01mj@732
|
467 }
|
mas01mj@732
|
468
|
mas01mj@732
|
469 /**
|
mas01mj@732
|
470 * Helper method for removing added <code>DisplayObject</code>s.
|
mas01mj@732
|
471 *
|
mas01mj@732
|
472 * <b>Update:</b> This method should no longer fail if the provided <code>DisplayObject</code>
|
mas01mj@732
|
473 * has already been removed.
|
mas01mj@732
|
474 **/
|
mas01mj@732
|
475 protected function removeChild(child:DisplayObject):DisplayObject {
|
mas01mj@732
|
476 if(child == null) {
|
mas01mj@732
|
477 return null;
|
mas01mj@732
|
478 }
|
mas01mj@732
|
479 try {
|
mas01mj@732
|
480 return getContext().removeChild(child);
|
mas01mj@732
|
481 }
|
mas01mj@732
|
482 catch(e:Error) {
|
mas01mj@732
|
483 }
|
mas01mj@732
|
484 return null;
|
mas01mj@732
|
485 }
|
mas01mj@732
|
486 }
|
mas01mj@732
|
487 }
|