2. Who am I?
Bjorn Schultheiss
Developer
Adslot
Front end developer
Flash, Flex and now even some Javascript
Large projects including http://www.adchamp.com
Topic Presenter
Designing Testable Code Bjorn Schultheiss
5. Testable code you say
This presentation will cover
• How to look at OO
• Static methods and Global State
• Separation of object construction and logic
• Constructor Injection vs Setter Injection
• Presentation Model
Topic Presenter
Designing Testable Code Bjorn Schultheiss
7. And why would I be interested?
This presentation is targeted at
• Any developer creating heavy client side applications
• Focused specifically on Flex but the same principals
apply to other web languages and frameworks
• you love that feeling from watching a test pass
Topic Presenter
Designing Testable Code Bjorn Schultheiss
8. Tell me about Flex Unit
This talk is not about Flexunit
• Flex developer’s best friend
• Created by the community
• Endorsed by Adobe (integrated in FB)
• Easy to get started with
Topic Presenter
Designing Testable Code Bjorn Schultheiss
10. What are unit tests?
Topic Presenter
Designing Testable Code Bjorn Schultheiss
11. I knew you cowboys were here
Topic
Designing Testable Code
Presenter
Bjorn Schultheiss
12. • They are written by software engineers, not test
engineers.
• They are better written as you code, not after you’ve
finished
Topic Presenter
Designing Testable Code Bjorn Schultheiss
13. The only good excuse not to be writing them is because
you don’t know how.
Topic Presenter
Designing Testable Code Bjorn Schultheiss
14. So what do i need to know?
Topic Presenter
Designing Testable Code Bjorn Schultheiss
15. How to think about OO
• OO is about the relationship between data and
code
• data represents the state of an object
• code modifies that state
Topic Presenter
Designing Testable Code Bjorn Schultheiss
16. Procedural
public class ImageEditor
{
public function crop(image:Bitmap, size:Rectangle):Bitmap
{
// do something
}
Topic Presenter
Designing Testable Code Bjorn Schultheiss
17. Better
public class ImageEditor
{
private var _image:Bitmap;
public function ImageEditor(image:Bitmap) {
_image = image;
}
public function crop(size:Rectangle):void
{
// do something
}
}
Topic Presenter
Designing Testable Code Bjorn Schultheiss
18. Global State
• Object state is subject to garbage collection
• Global state is subject to life of the session
Topic Presenter
Designing Testable Code Bjorn Schultheiss
19. Global State
a = new X() -->
Topic Presenter
Designing Testable Code Bjorn Schultheiss
20. Global State
Y
a = new X() --> Z
X
Q
Topic Presenter
Designing Testable Code Bjorn Schultheiss
21. Global State
Y
a = new X() --> Z
X
Q
b = new X() -->
Topic Presenter
Designing Testable Code Bjorn Schultheiss
22. Global State
Y
a = new X() --> Z
X
Q
Y
b = new X() --> Z
X
Q
Topic Presenter
Designing Testable Code Bjorn Schultheiss
23. Global State
Y
a = new X() --> Z
a.doSomething(); X
Q
Y
b = new X() --> Z
X
Q
Topic Presenter
Designing Testable Code Bjorn Schultheiss
24. Global State
Y
a = new X() --> Z
a.doSomething(); X
Q
Y
b = new X() --> Z
b.doSomething(); X
Q
Topic Presenter
Designing Testable Code Bjorn Schultheiss
25. Global State
Y
a = new X() --> Z
a.doSomething(); X
Q
a == b
Y
b = new X() --> Z
b.doSomething(); X
Q
Topic Presenter
Designing Testable Code Bjorn Schultheiss
26. Global State
Y
a = new X() --> Z
a.doSomething(); X
Q
GS
a == b
Y
b = new X() --> Z
b.doSomething(); X
Q
Topic Presenter
Designing Testable Code Bjorn Schultheiss
27. Global State
• Inconsistent results
• Order of tests matter
• Something the tester doesn’t control
Topic Presenter
Designing Testable Code Bjorn Schultheiss
31. package
{
public class AppSettings
{
private static const _instance:AppSettings = new AppSettings(Lock);
private var _state1:Object;
private var _state2:Object;
private var _state3:Object;
public static function get instance():AppSettings {
return _instance;
}
public function AppSettings(lock:Class) {
if (lock!=Lock) throw new Error("cannot unlock");
}
}
}
internal class Lock {}
Topic Presenter
Designing Testable Code Bjorn Schultheiss
32. Singletons
• Singletons use global state
• the test doesn’t control the instantion of the
process
Topic Presenter
Designing Testable Code Bjorn Schultheiss
33. package
{
public class AppSettings
{
private static const _instance:AppSettings = new AppSettings(Lock);
private var _state1:Object;
private var _state2:Object;
private var _state3:Object;
public static function get instance():AppSettings {
return _instance;
}
public function AppSettings(lock:Class) {
if (lock!=Lock) throw new Error("cannot unlock");
}
}
}
internal class Lock {}
Topic Presenter
Designing Testable Code Bjorn Schultheiss
34. Singletons
• Singletons use global state
• the test doesn’t control the instantion of the
process
• secret collaborators
Topic Presenter
Designing Testable Code Bjorn Schultheiss
35. public class CreditCard
{
private var _gateway:PaymentGateway;
public function CreditCard()
{
gateway = ServiceLocator.getInstance().gateway;
}
public function chargeCard(value:Number):void
{
gateway.performTransaction(value);
}
}
var cc:CreditCard = new CreditCard();
cc.chargeCard(10);
Topic Presenter
Designing Testable Code Bjorn Schultheiss
36. Singletons
• Singletons use global state
• the test doesn’t control the instantion of the
process
• secret collaborators
• you may know the dependencies, but anyone that
comes after you is baffled!
Topic Presenter
Designing Testable Code Bjorn Schultheiss
40. Locator in action
class House {
public function House(locator:Locator) {
// what needs to be mocked in test?
}
}
Topic Presenter
Designing Testable Code Bjorn Schultheiss
41. Use revealed
class House {
private var _door:Door;
private var _roof:Roof;
private var _window:Window
public function House(locator:Locator) { API gave us
_door = locator.getDoor();
_roof = locator.getRoof(); no help
_window = locator.getWindow();
}
}
Topic Presenter
Designing Testable Code Bjorn Schultheiss
42. An API that helps
class House {
private var _door:Door;
private var _roof:Roof;
private var _window:Window
public function House(door:Door, roof:Roof, window:Window) {
_door = door;
_roof = roof;
_window = window;
}
}
Topic Presenter
Designing Testable Code Bjorn Schultheiss
43. Similar Anti-Patterns
I didn’t ask for that!!
• aka Locator
• aka Context
• aka Manager
• Hides true dependencies
• Breaks law of demeter
Topic Presenter
Designing Testable Code Bjorn Schultheiss
44. Constructor vs Setter injection
• An order of instantiation
Topic Presenter
Designing Testable Code Bjorn Schultheiss
45. Setter example
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.collections.IList;
import mx.rpc.AsyncToken;
public var userService:Service;
public function findUsers():void {
userService.findAll();
userService.addEventListener("onResult", onResult);
}
public function onResult(result:Object):void {
users.dataprovider = new ArrayCollection(result);
}
]]>
</fx:Script>
<s:Button label="find all users" click="findUsers();" />
<s:List id="users" />
</s:Group>
Topic Presenter
Designing Testable Code Bjorn Schultheiss
46. Constructor example
public class ShowUserModel
{
[Bindable]
public var users:IList;
private var _service:Service;
public function ShowUserModel(service:Service)
{
_service = service;
_service.addEventListener("onResult", onResult);
}
public function findUsers():void
{
_service.findAll();
}
private function onResult(result:Object):void {
users = new ArrayCollection(result);
}
}
Topic Presenter
Designing Testable Code Bjorn Schultheiss
47. Instantiation example
[Test]
public function testShowUsersComponent():void
{
var service:Service = new Service("Users");
var component:ShowUsersComponent = new ShowUsersComponent();
component.service = service;
component.findUsers();
}
[Test]
public function testShowUsersModel():void
{
var service:Service = new Service("Users");
var model:ShowUsersModel = new ShowUsersModel(service);
model.findUsers();
}
Topic Presenter
Designing Testable Code Bjorn Schultheiss
48. How does this relate to unit
testing?
Topic Presenter
Designing Testable Code Bjorn Schultheiss
49. How does this relate to unit
testing?
Unit testing as the name
implies you test a Class (unit)
in isolation
Topic Presenter
Designing Testable Code Bjorn Schultheiss
50. If your class mixes Object
construction and logic you will
never be able to achieve
isolation
Topic Presenter
Designing Testable Code Bjorn Schultheiss
51. In order to unit test you
need to separate your
object graph construction
from the logic into 2
different classes
Topic Presenter
Designing Testable Code Bjorn Schultheiss
52. The end goal is to have classes with either logic or “new”
operators
Topic Presenter
Designing Testable Code Bjorn Schultheiss
53. Construction and logic mixed
public class House
{
private var _kitchen:Kitchen = new Kitchen();
private var _isLocked:Boolean;
public function get isLocked():Boolean {
return _isLocked;
}
public function lock() {
_kitchen.lock();
_isLocked = true;
}
}
Topic Presenter
Designing Testable Code Bjorn Schultheiss
54. Injection example
public class House
{
private var _kitchen:Kitchen;
private var _isLocked:Boolean;
public function House(kitchen:Kitchen) {
_kitchen = kitchen;
}
public function get isLocked():Boolean {
return _isLocked;
}
public function lock() {
_kitchen.lock();
_isLocked = true;
}
}
Topic Presenter
Designing Testable Code Bjorn Schultheiss
55. Construction example
function build():House {
return new House(new Kitchen(
new Sink(),
new Dishwasher(),
new Refrigerator())
);
}
Topic Presenter
Designing Testable Code Bjorn Schultheiss
56. lets look at writing a unit test
Topic Presenter
Designing Testable Code Bjorn Schultheiss
57. Writing a unit test
to test a method first you need to instantiate an object
• Specifically the class or component to be tested
• Any collaborators (real or mock).
Topic Presenter
Designing Testable Code Bjorn Schultheiss
58. [Test]
public function testHouse():void
{
var kitchen:Kitchen = new Kitchen();
var house:House = new House(kitchen);
house.testMethod();
}
Topic Presenter
Designing Testable Code Bjorn Schultheiss
60. Spare me
Topic
Designing Testable Code
Presenter
Bjorn Schultheiss
61. Testing UI Components
Possible but generally a pain, why?
• test a style is applied
• mimic user interaction
• logic is is mixed with view
Topic Presenter
Designing Testable Code Bjorn Schultheiss
62. [Before(async,ui)]
public function setUp() : void
{
myButton = new MyButton();
Async.proceedOnEvent( this, myButton, FlexEvent.CREATION_COMPLETE, 100 );
UIImpersonator.addChild( myButton );
}
[Test(async,ui)]
public function myButton_myStyle_defaultValue() : void
{
Assert.assertEquals( myButton.getStyle( "myStyle" ), "expectedDefaultValue" );
}
Topic Presenter
Designing Testable Code Bjorn Schultheiss
64. Presentation Models
http://martinfowler.com/eaaDev/PresentationModel.html
Represent the state and behaviour of the presentation independently of the GUI controls
used in the interface
• uses Binding to interact with view
• also handles events from view
• a pattern used in popular frameworks
• great for unit testing
Topic Presenter
Designing Testable Code Bjorn Schultheiss
65. Presentation Model example
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009">
package presentation
<fx:Script>
{
<![CDATA[
[Bindable]
import presentation.HelloWorldModel;
public class HelloWorldModel
[Bindable]
{
public var model:HelloWorldModel;
public var label:String = "Hello";
]]>
</fx:Script>
public function clickHandler():void
<s:Label text="{ model.label }"
{
click="model.clickHandler();" />
trace("Is it me your looking for?");
</s:Group>
}
}
}
Topic Presenter
Designing Testable Code Bjorn Schultheiss
66. Business logic and PM’s
Leave me out of it!
• Presentation Models and Views have a 1 to 1
relationship
• Business logic is best separated from PM’s
• PM’s know about Business/Application classes,
those classes know nothing about PM’s
Topic Presenter
Designing Testable Code Bjorn Schultheiss
67. Well on your way
Topic
Designing Testable Code
Presenter
Bjorn Schultheiss
I want to talk about future development opportunities for the adbuilder,\nmore premium engaging forms of advertising, and how to use html as an\noption for ad deployment.\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
- doesnt interact with class data\n- users passed in to method\n