Introduction to TDD & FlexUnit

+3

No comments posted yet

Comments

Slide 1

Presenter: Thanh Tran Email: trongthanh@gmail.com Twitter: @trongthanh Date: 18 June 2010 Test-driven Development & Flex Unit

Slide 2

Content Test-driven Development & Unit Testing TDD Overview Unit Testing & its benefits FlexUnit Sample Walkthrough Features Briefing Assertion Methods Authentic examples TDD Benefits & Vulnerabilities FlexUnit, when we should apply? References

Slide 3

Test-driven development (TDD) is a software development technique where developers: TDD Overview

Slide 4

related to the test-first programming concepts of Extreme Programming (XP) one of the techniques in the Agile methodologies requires write test before implement "keep it simple, stupid" (KISS) "You ain't gonna need it" (YAGNI) TDD Overview (contd.)

Slide 5

Unit Testing Facilitates change: allows the programmer to refactor code at a later date, and make sure the module still works correctly Simplifies integration: testing the parts of a program first and then testing the sum of its parts, integration testing becomes much easier

Slide 6

Unit Testing Documentation provides a sort of living documentation of the system Ex: [Test( description = "This tests replace" )] public function testReplace(): void { var str: String = "Today is Monday, Today is monday, Today is moNday, Today is monDay"; str = StringUtil.replace(str, "Monday", "Saturday"); Assert.assertEquals("Today is Saturday, Today is Saturday, Today is Saturday, Today is Saturday", str); }

Slide 7

Unit Testing Design-driven each unit test can be seen as a design element specifying classes, methods, and observable behavior Example: (next slide)

Slide 8

Unit Testing Example: this test will drive design of GetVideoItemService and VideoInfo [Test(order=2, async, description = "test get video info")] public function getInformationByID(): void { var service: GetVideoItemService = new GetVideoItemService(); var asyncHandler: Function = Async.asyncHandler(this, getVideoInfoHandler, 500, null, timeOutHandler); service.addEventListener(ServiceEvent.GOT_VIDEO_ITEM_INFO, asyncHandler); service.getVideoItemInfo("1"); } private function getVideoInfoHandler(event: ServiceEvent, passThroughData: Object): void { var videoInfo: VideoInfo = VideoInfo(event.data); Assert.assertEquals("Toyota Video 1", videoInfo.title); Assert.assertEquals("http://tdn.tv/toyota/images/thumbs/tdn.jpg", videoInfo.urlThumbnail); Assert.assertEquals("Author 6", videoInfo.author); /*...*/ }

Slide 9

FlexUnit

Slide 10

Introduction FlexUnit is a unit testing framework for Flex and ActionScript 3.0 applications and libraries. It mimics the functionality of JUnit, a Java unit testing framework, and comes with a graphical test runner.

Slide 11

FlexUnit walkthrough Case Study: Create a calculator.

Slide 12

FlexUnit walkthrough 1. First, let's setting up project's and folders:

Slide 13

FlexUnit walkthrough 2. Create new folder “unit_test” in project's root and create another project for unit test.

Slide 14

FlexUnit walkthrough For not overwriting existing files and folders of the main project, create an empty project for unit test

Slide 15

FlexUnit walkthrough Set the new project settings as following: Output: - bin/TestRunner.swf - 1024 x 768 Classpath: - lib - src - unit_test SWC Libraries: - lib

Slide 16

FlexUnit walkthrough 3. Copy FlexUnit's swc to lib folders: flexunit-4.0.0.swc (FlexUnit core) flexunit-uilistener-4.0.0.swc (Flex-based graphical runner)

Slide 17

FlexUnit walkthrough 4. Create test suite: TestSuite is a collection of TestCases and possibly other TestSuites. package unittest { [Suite] [RunWith("org.flexunit.runners.Suite")] public class TestSuite { } }

Slide 18

FlexUnit walkthrough 5. Create first test case: A TestCase is a collection of TestMethods that share a common test environment. package unittest.testcases { public class TestCalculatorUtil { } }

Slide 19

FlexUnit walkthrough 6. Create first test method: A TestMethod is the smallest unit of the testing framework. A test method executes code and checks an outcome. In FlexUnit4, your methods must be decorated by a piece of [Test] metadata package unittest.testcases { import org.flexunit.Assert; public class TestCalculatorUtil { [Test (description="test add")] public function testAdd(): void { Assert.assertEquals(5, CalculatorUtil.add(2, 3)); } } }

Slide 20

FlexUnit walkthrough Go back to TestSuite and add the TestCase: package unittest { import unittest.testcases.TestCalculatorUtil; [Suite] [RunWith("org.flexunit.runners.Suite")] public class TestSuite { public var testCase1: TestCalculatorUtil; } }

Slide 21

FlexUnit walkthrough 7. Create the TestRunner.mxml to run the test: <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:ui="http://www.adobe.com/2009/flexUnitUIRunner" creationComplete="runMe()" > <mx:Script> <![CDATA[ import unittest.TestSuite; import org.flexunit.listeners.UIListener; import org.flexunit.runner.FlexUnitCore; private var core:FlexUnitCore; public function runMe():void { core = new FlexUnitCore(); //Listener for the UI core.addListener( new UIListener( uiListener )); //run test suite core.run( TestSuite); } ]]> </mx:Script> <ui:TestRunnerBase id="uiListener" width="100%" height="100%" /> </mx:Application>

Slide 22

FlexUnit walkthrough At this time the unit tests are not compilable because we haven't implement anything yet. However, we can consider this is also a failed test case.

Slide 23

FlexUnit walkthrough 8. Create the class and functions to match the design in test method but don't implement any logic yet. This step is to make the tests compilable but expect to failed. package calculator.utils { public class CalculatorUtil { public static function add(a: Number, b: Number): Number { return NaN; } } }

Slide 24

FlexUnit walkthrough Compile and run the test runner, see the test fails:

Slide 25

FlexUnit walkthrough 9. Implement the logic to pass the test: public static function add (a: Number, b: Number): Number { return a + b; }

Slide 26

FlexUnit walkthrough 10. Run the test to see if you pass:

Slide 27

FlexUnit walkthrough This concludes a UnitTest life cycle. Continue adding new features by repeating the steps from creating new test method.

Slide 28

FlexUnit features briefing Flex or ActionScript 3 FlexUnit works with both Flex or AS3-only projects. Metadata By using metadata [Test] [Suite]... tests no longer need any special name or extends special classes

Slide 29

FlexUnit features briefing Before and After [Before] methods will be run before each test method. [After] methods will be run after each test method. [Before] public function runBeforeEveryTest():void { simpleMath = new SimpleMath(); } [Before] public function alsoRunBeforeEveryTest():void { simpleMath1 = new SimpleMath(); } [After] public function runAfterEveryTest():void { simpleMath = null; simpleMath1 = null; }

Slide 30

FlexUnit features briefing BeforeClass and AfterClass [BeforeClass] and [AfterClass] allow you to define static methods that will run once before and after the entire test class [BeforeClass] public static function runBeforeClass():void { //run for one time before all test cases } [AfterClass] public static function runAfterClass():void { // run for one time after all test cases }

Slide 31

FlexUnit features briefing Exception Handling The expects parameter in [Test] allows you to indicate that a given test is expected to throw an exception [Test(expects="flash.errors.IOError")] public function doIOError():void { //a test which causes an IOError } //OR [Test(expects="TypeError")] public function divisionWithException():void { simpleMath.divide( 11, 0 ); }

Slide 32

Ignore Ignore metadata can be added before any test case you want to ignore. Unlike commenting out a test, these tests will still appear in the output for reminding. [Ignore("Not Ready to Run")] [Test] public function multiplication():void { assertEquals(15, simpleMath.multiply(3, 5)); } FlexUnit features briefing

Slide 33

FlexUnit features briefing Async To specify which tests need asynchronous support, use the async parameter. Async tests are necessary for some particular test like services, time-based or event-based parts. [Before(async,timeout="250")] public function setMeUp():void {/*...*/} [After(async,timeout="250")] public function allDone():void {/*...*/} [Test(async,timeout="500")] public function doSomethingAsynchronous():void { //Async.proceedOnEvent( testCase, target, eventName ); //Async.failOnEvent( testCase, target, eventName ); //Async.handleEvent( testCase, target, eventName, eventHandler ); //Async.asyncHandler( testCase, eventHandler ); //Async.asyncResponder( testCase, responder ); }

Slide 34

FlexUnit features briefing Ex (again): [Test(order=2, async, description = "test get video info")] public function getInformationByID(): void { var service: GetVideoItemService = new GetVideoItemService(); var asyncHandler: Function = Async.asyncHandler(this, getVideoInfoHandler, 500, null, timeOutHandler); service.addEventListener(ServiceEvent.GOT_VIDEO_ITEM_INFO, asyncHandler); service.getVideoItemInfo("1"); } private function getVideoInfoHandler(event: ServiceEvent, passThroughData: Object): void { var videoInfo: VideoInfo = VideoInfo(event.data); Assert.assertEquals("Toyota Video 1", videoInfo.title); Assert.assertEquals("http://tdn.tv/toyota/images/thumbs/tdn.jpg", videoInfo.urlThumbnail); Assert.assertEquals("Author 6", videoInfo.author); /*...*/ }

Slide 35

FlexUnit features briefing Hamcrest Hamcrest is a library of matcher objects allowing 'match' rules to be defined declaratively. Use assertThat() for Hamcrest assertion //Example: [Test] public function testGreaterThan():void { assertThat( 11, greaterThan(3) ); } [Test] public function isItInHere():void { var someArray:Array = [ 'a', 'b', 'c', 'd', 'e', 'f' ]; assertThat( someArray, hasItems("b", "c") ); } assertThat(valueToMatch:Object, matcher:Matcher); assertThat(assertionDescription:String, valueToMatch:Object, matcher:Matcher);

Slide 36

Assertion methods

Slide 37

Some Authentic examples

Slide 38

TDD Benefits & Vulnerabilities

Slide 39

TDD's Benefits gives greater level of confidence in the code significantly reduces the effort of QA drives the design of a program total code implementation time is typically SHORTER leads to more modularized, flexible, and extensible code

Slide 40

TDD's Vulnerabilities cannot be expected to catch every error in the program and will not catch integration errors or broader system-level errors Without entire organization support/belief, management may feel that time spent writing tests is wasted Writing code for a unit test is as likely to be at least as buggy as the code it is testing Unexpected gaps in test coverage may occur which leads to false confidence / bugs undetected The tests may share the same blind spots with the code due to misunderstanding of requirements

Slide 41

FlexUnit, when should be applied?

Slide 42

FlexUnit, when should it be applied? 1. Testing utilities & helpers 2. Testing GUI 3. Testing library or framework API 4. Testing components integration 5. Testing validators. 6. Testing view components 7. Testing services 8. Testing reusable blocks of code or functions. 9. Testing MVC workflow YES NO YES YES NO YES YES NO NO

Slide 43

References FlexUnit: http://flexunit.org Wiki: Unit Testing http://en.wikipedia.org/wiki/Unit_testing Wiki: Test-driven Development http://en.wikipedia.org/wiki/Test-driven_development Another FlexUnit tutorial: http://elromdesign.com/blog/2010/03/10/test-driven-development-tdd-with-flexunit-4-complete-tutorial/ Hamcrest-as3: http://github.com/drewbourne/hamcrest-as3

Slide 44

Q & A

Slide 45

Thank you

Summary: Slides of my presentation to introduce TDD and FlexUnit

Tags: flexunit tdd unit testing flash actionscript

URL: