Unit Testing ActionScript and FlexMichael Labriola  |  Senior Consultant, Digital Primates@mlabriola | labriola@digitalprimates.net
Who Am I?Michael LabriolaSenior ConsultantDigital PrimatesClient side architect specializing in Adobe FlexArchitect and developer of FluintLead architect and developer of FlexUnit4.xBenevolent Dictator of the Spoon FrameworkCo-Author of Flex Training from the Source SeriesTeam MentorFan of working code2
Before We BeginThis lab is broken into five main tasks with various exercises along the wayIn 90 minutes, if things go well, we will complete tasks one through four with some discussion along the wayTask five is something I would strongly advise you take a bit of time to review later. It is a full rework of the application to be testable.The lab workbook and all lesson files are available for downloadAt the end of several lessons there are ‘Advanced’ exercises. People will move at different rates through the content. If you find yourself done with a Task and have time, ponder the advanced exercise they will help demonstrate points in a Socratic wayThey can be treated as thought exercises but work better if you actually try to implement3
Types of Testing - UnitUnit Testing - Our concern in this labUnit testing involves testing the smallest units of codeA single objectIt requires that the object be isolated.The test result should not be able to be affected by other objects It should not be affected by global stateWhen a unit test fails the source of the error should be immediately clearThis requirement for isolation means that some code cannot be unit testedAxiom - You can only unit test testable codeCreating testable code is both a question of implementation and of architectureMany people want to unit test but failIn my experience, this is usually because the code they wish to test is not testable in units4
Types of Testing - IntegrationIntegration TestingInvolves testing several (ideally tested) units togetherVery important part of testingYou need to know that individual objects work together properlyFailures are not as clearWhen an integration test fails, there are (n) places it could have failedAs a general rule, the moment we discuss any of the following words, we are discussing some form of integration test:AsynchronousServerLifecycleDisplayList5
Types of Testing - FunctionalAllows you to record and playback interactions with an applicationExtremely important; ensures that the application works to specificationMany units need to be working before you can produce a single testFailures are very unclearAny number of units could be responsible for the failureMany tools available:Flex Monkey – Open SourceTest CompleteRIATestHP QTPAnd more6
Exercise 1.17
Object GraphsTo understand unit testing we need understand object graphsThere are two types of objects we are concerned about Branch and LeafLeaf Nodes have no dependencies on other objects in your code (they will have dependencies on simple types and some flash player objects)Trivial to testBranch Nodes have dependencies on other objectsMore difficult and sometimes impossible to test8
Creating ObjectsYou will always have both types in your system, however, we often have too many dependencies because we forget some simple things:An object is supposed to have one responsibility.Single Responsibility Principle. Objects with (n) responsibilities will be much     harder to test effectivelySecond objects shouldn’t reach into each other.It breaks encapsulationDon’t violate the Law of DemetermyObject.childObject.grandChildObject.property9
Exercise 1.2 and 1.310
Testing FrameworkFlexUnit 4 is a unit testing frameworkYou don’t need a framework to testYou already test each time you walk through the same actions to vet a piece of codeTesting frameworks only exist to:Automate this effort so the tests can be run again and again easilyStandardize the way tests are constructed so they are understandable to others11
AssertionsAssertions are a tool used to reveal whether or not a piece of code is working as expected. They take the form of a strong statement indicating the result. For example, if you add the numbers 2 and 3.		result = 2 + 3;You can assert that the result is 5. You do so as you are sure that no other answer is satisfactory and that a different answer is just plain wrong.assertEquals( 5, result );If this assertion is not true, meaning that result is not equal to 5, then you can conclude that the plus operator no longer works correctly in all cases. This is the basis of testing.12
TestA Test is just a public method of an objectThe method is decorated by a special [Test] metadata which allows FlexUnit 4 to recognize it as test[Test] public function shouldSeeBlueSky():void { varsky:Sky = new Sky(); assertEquals( “blue”, sky.color ); } Tests contain one (preferable) or more assertions indicating your belief about the state of the object under test or the result of a method invoked on the objectEach test is discrete. It should not depend on other tests or the order the tests are run.13
Test CaseA Test Case is a collection of related Tests in a single class[Test] public function shouldSeeBlueSky():void { varsky:Sky = new Sky(); assertEquals( “blue”, sky.color ); }[Test] public function shouldNotSeeClouds():void { varsky:Sky = new Sky(); assertNull(sky.clouds); } 14
Test Case SetupAs all tests in a single Test Case should be related, they often can share setupThe combination of the setup/environment needed to run a test is called a Test FixtureFlexUnit 4 facilitates sharing test fixtures by allowing you to mark a method with Before or After metadata. This indicates the method should be run before or after every test method.[Before] public function andTheSkyWasCreated():void { sky = new Sky(); }[After] public function letItFall():void { sky = null;} 15
Test Case RulesFlexUnit 4 offers one more way to configure the test case fixture, rules.You can think of rules as a way to move things that would happen in the Before and After into a separate object. This makes it easier to share this configuration code amongst multiple test cases[Rule] public varcreateAndDestroySky:CreateAndDestroySkyRule = new CreateAndDestroySkyRule();16
Test SuiteA Test Suite is a collection of Test Cases and other Test Suitespackage flexUnitTests {  [Suite]  [RunWith("org.flexunit.runners.Suite")]  public class CurrencyConverterSuite {    public var test1:ClearSkyTests;    public var test2:StormySkyTests;  }}17
Exercise 2.1 and 2.218
MatchersThe process of performing multiple assertions can become complicatedImagine a scenario where you need to verify that 2 points are identical[Test] public function shouldBeTheSamePoint():void { assertEquals( pt1.x, pt2.x ); assertEquals( pt1.y, pt2.y ); assertEquals( pt1.z, pt2.x ); }At some point your test cases become littered with all of the work required to do the assertionsTo address this problem, FlexUnit works with something called matchers that allow you to move this work into a separate object19
HamcrestUsing matchers, the code can look more like this:[Test] public function shouldBeTheSamePoint():void { assertThat( pt1, isSamePoint( pt2 ) ); }The code becomes more readable and the matching logic is contained elsewhere.There is a collection of matchers that can be used with FlexUnit as well as any ActionScript project that can use specialized matching, it is called Hamcrest-as3For more information: https://github.com/drewbourne/hamcrest-as320
Exercise 2.321
Exercise 3.1-3.222
Branches versus NodesWe talked about branches in the abstract, but here is something more concrete.Even though we extracted the PercentChangeFormatter from MarketInfo, it is still a branch node, not a leaf node23MarketInfoPercentChangeFormatterNumberFormatter
CombinatorialIf you aren’t careful with these sorts of dependencies, you end up with combinatorial tests. This results in a lot of test duplication… technically this is because you can’t identify independent variables.The PercentChangeFormatter really just modifies the String returned from the NumberFormatter a little. As they exist now we really end up testing the both of these objects together… which is an integration test…24PercentChangeFormatterNumberFormatter
Exercise 4.125
Seams and MocksThe cleanest way to deal with this is to create a seam.If we provide the needed NumberFormatter to the PercentChangeFormatter, we create a seamWhat can we do with that seam?We could build the PercentChangeFormatter with a substitute NumberFormatterThis will eliminate the combinations and allow us to test only one class (a unit)There are two types of substitutes we can use… fakes and mocksFakes are just dumb objects that conform to the same interfaceMocks are intelligent objects that keep track of what happened to them and know how they should respondFor this Task we will use one of many available mocking frameworks, named Mockolate. 26
Exercise 4.227
Additional Resources28Google Testing Bloghttp://googletesting.blogspot.com/FlexUnithttp://flexunit.org/FlexUnit Tutorialshttp://tutorials.digitalprimates.net/flexunit.htmlHamcresthttps://github.com/drewbourne/hamcrest-as3Mockolatehttp://mockolate.org/My Bloghttp://www.digitalprimates.net/author/codeslinger/
29

L2624 labriola

  • 1.
    Unit Testing ActionScriptand FlexMichael Labriola | Senior Consultant, Digital Primates@mlabriola | labriola@digitalprimates.net
  • 2.
    Who Am I?MichaelLabriolaSenior ConsultantDigital PrimatesClient side architect specializing in Adobe FlexArchitect and developer of FluintLead architect and developer of FlexUnit4.xBenevolent Dictator of the Spoon FrameworkCo-Author of Flex Training from the Source SeriesTeam MentorFan of working code2
  • 3.
    Before We BeginThislab is broken into five main tasks with various exercises along the wayIn 90 minutes, if things go well, we will complete tasks one through four with some discussion along the wayTask five is something I would strongly advise you take a bit of time to review later. It is a full rework of the application to be testable.The lab workbook and all lesson files are available for downloadAt the end of several lessons there are ‘Advanced’ exercises. People will move at different rates through the content. If you find yourself done with a Task and have time, ponder the advanced exercise they will help demonstrate points in a Socratic wayThey can be treated as thought exercises but work better if you actually try to implement3
  • 4.
    Types of Testing- UnitUnit Testing - Our concern in this labUnit testing involves testing the smallest units of codeA single objectIt requires that the object be isolated.The test result should not be able to be affected by other objects It should not be affected by global stateWhen a unit test fails the source of the error should be immediately clearThis requirement for isolation means that some code cannot be unit testedAxiom - You can only unit test testable codeCreating testable code is both a question of implementation and of architectureMany people want to unit test but failIn my experience, this is usually because the code they wish to test is not testable in units4
  • 5.
    Types of Testing- IntegrationIntegration TestingInvolves testing several (ideally tested) units togetherVery important part of testingYou need to know that individual objects work together properlyFailures are not as clearWhen an integration test fails, there are (n) places it could have failedAs a general rule, the moment we discuss any of the following words, we are discussing some form of integration test:AsynchronousServerLifecycleDisplayList5
  • 6.
    Types of Testing- FunctionalAllows you to record and playback interactions with an applicationExtremely important; ensures that the application works to specificationMany units need to be working before you can produce a single testFailures are very unclearAny number of units could be responsible for the failureMany tools available:Flex Monkey – Open SourceTest CompleteRIATestHP QTPAnd more6
  • 7.
  • 8.
    Object GraphsTo understandunit testing we need understand object graphsThere are two types of objects we are concerned about Branch and LeafLeaf Nodes have no dependencies on other objects in your code (they will have dependencies on simple types and some flash player objects)Trivial to testBranch Nodes have dependencies on other objectsMore difficult and sometimes impossible to test8
  • 9.
    Creating ObjectsYou willalways have both types in your system, however, we often have too many dependencies because we forget some simple things:An object is supposed to have one responsibility.Single Responsibility Principle. Objects with (n) responsibilities will be much harder to test effectivelySecond objects shouldn’t reach into each other.It breaks encapsulationDon’t violate the Law of DemetermyObject.childObject.grandChildObject.property9
  • 10.
  • 11.
    Testing FrameworkFlexUnit 4is a unit testing frameworkYou don’t need a framework to testYou already test each time you walk through the same actions to vet a piece of codeTesting frameworks only exist to:Automate this effort so the tests can be run again and again easilyStandardize the way tests are constructed so they are understandable to others11
  • 12.
    AssertionsAssertions are atool used to reveal whether or not a piece of code is working as expected. They take the form of a strong statement indicating the result. For example, if you add the numbers 2 and 3. result = 2 + 3;You can assert that the result is 5. You do so as you are sure that no other answer is satisfactory and that a different answer is just plain wrong.assertEquals( 5, result );If this assertion is not true, meaning that result is not equal to 5, then you can conclude that the plus operator no longer works correctly in all cases. This is the basis of testing.12
  • 13.
    TestA Test isjust a public method of an objectThe method is decorated by a special [Test] metadata which allows FlexUnit 4 to recognize it as test[Test] public function shouldSeeBlueSky():void { varsky:Sky = new Sky(); assertEquals( “blue”, sky.color ); } Tests contain one (preferable) or more assertions indicating your belief about the state of the object under test or the result of a method invoked on the objectEach test is discrete. It should not depend on other tests or the order the tests are run.13
  • 14.
    Test CaseA TestCase is a collection of related Tests in a single class[Test] public function shouldSeeBlueSky():void { varsky:Sky = new Sky(); assertEquals( “blue”, sky.color ); }[Test] public function shouldNotSeeClouds():void { varsky:Sky = new Sky(); assertNull(sky.clouds); } 14
  • 15.
    Test Case SetupAsall tests in a single Test Case should be related, they often can share setupThe combination of the setup/environment needed to run a test is called a Test FixtureFlexUnit 4 facilitates sharing test fixtures by allowing you to mark a method with Before or After metadata. This indicates the method should be run before or after every test method.[Before] public function andTheSkyWasCreated():void { sky = new Sky(); }[After] public function letItFall():void { sky = null;} 15
  • 16.
    Test Case RulesFlexUnit4 offers one more way to configure the test case fixture, rules.You can think of rules as a way to move things that would happen in the Before and After into a separate object. This makes it easier to share this configuration code amongst multiple test cases[Rule] public varcreateAndDestroySky:CreateAndDestroySkyRule = new CreateAndDestroySkyRule();16
  • 17.
    Test SuiteA TestSuite is a collection of Test Cases and other Test Suitespackage flexUnitTests { [Suite] [RunWith("org.flexunit.runners.Suite")] public class CurrencyConverterSuite { public var test1:ClearSkyTests; public var test2:StormySkyTests; }}17
  • 18.
  • 19.
    MatchersThe process ofperforming multiple assertions can become complicatedImagine a scenario where you need to verify that 2 points are identical[Test] public function shouldBeTheSamePoint():void { assertEquals( pt1.x, pt2.x ); assertEquals( pt1.y, pt2.y ); assertEquals( pt1.z, pt2.x ); }At some point your test cases become littered with all of the work required to do the assertionsTo address this problem, FlexUnit works with something called matchers that allow you to move this work into a separate object19
  • 20.
    HamcrestUsing matchers, thecode can look more like this:[Test] public function shouldBeTheSamePoint():void { assertThat( pt1, isSamePoint( pt2 ) ); }The code becomes more readable and the matching logic is contained elsewhere.There is a collection of matchers that can be used with FlexUnit as well as any ActionScript project that can use specialized matching, it is called Hamcrest-as3For more information: https://github.com/drewbourne/hamcrest-as320
  • 21.
  • 22.
  • 23.
    Branches versus NodesWetalked about branches in the abstract, but here is something more concrete.Even though we extracted the PercentChangeFormatter from MarketInfo, it is still a branch node, not a leaf node23MarketInfoPercentChangeFormatterNumberFormatter
  • 24.
    CombinatorialIf you aren’tcareful with these sorts of dependencies, you end up with combinatorial tests. This results in a lot of test duplication… technically this is because you can’t identify independent variables.The PercentChangeFormatter really just modifies the String returned from the NumberFormatter a little. As they exist now we really end up testing the both of these objects together… which is an integration test…24PercentChangeFormatterNumberFormatter
  • 25.
  • 26.
    Seams and MocksThecleanest way to deal with this is to create a seam.If we provide the needed NumberFormatter to the PercentChangeFormatter, we create a seamWhat can we do with that seam?We could build the PercentChangeFormatter with a substitute NumberFormatterThis will eliminate the combinations and allow us to test only one class (a unit)There are two types of substitutes we can use… fakes and mocksFakes are just dumb objects that conform to the same interfaceMocks are intelligent objects that keep track of what happened to them and know how they should respondFor this Task we will use one of many available mocking frameworks, named Mockolate. 26
  • 27.
  • 28.
    Additional Resources28Google TestingBloghttp://googletesting.blogspot.com/FlexUnithttp://flexunit.org/FlexUnit Tutorialshttp://tutorials.digitalprimates.net/flexunit.htmlHamcresthttps://github.com/drewbourne/hamcrest-as3Mockolatehttp://mockolate.org/My Bloghttp://www.digitalprimates.net/author/codeslinger/
  • 29.

Editor's Notes

  • #10 Image Copyright Wenger