Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Faking it with Mockolate

Avatar for drewbourne drewbourne
November 30, 2011

Faking it with Mockolate

Avatar for drewbourne

drewbourne

November 30, 2011
Tweet

More Decks by drewbourne

Other Decks in Programming

Transcript

  1. The quality that makes you go to great effort to

    reduce overall energy expenditure. It makes you write labour saving programs that other people find useful, and document what you wrote so that you don’t have to answer so many questions about it. LAZINESS
  2. The anger you feel when the computer is being lazy.

    This makes you write programs that don’t react to your needs, but actually anticipates them. Or at least pretends to. IMPATIENCE
  3. Excessive pride, the sort of thing Zeus zaps you for.

    Also the quality that makes you write (and maintain) programs that other people won’t want to say bad things about. HUBRIS
  4. ?

  5. [Test] public function test_should_be_short():void { assertThat(test.lines, lessThan(20)); } [Test] public

    function test_should_choose_the_right_assertions():void { assertThat(test.assertions, use("hamcrest")); } [Test] public function test_should_use_the_same_level_of_abstraction ():void { assertThat(test.subject, didNotExposePrivates()); assertThat(test.collaborators, didNotViolateDemeter()); } [Test] public function test_should_not_repeat_previous_assertions():void { assertThat(test.assertionCount, between(1,3)); assertThat(test.assertions, everyItem(hasProperties({ description: not(emptyString()) })))); }
  6. [Test] public function test_colloborators_should_not_be_modified_for_testing():void { var component:UIComponentForTesting = new UIComponentForTesting

    (); var container:Container = new Container(); container.addChild(component); assertThat(component.invalidatePropertiesWasCalled, isTrue()); } internal class UIComponentForTesting extends UIComponent { public var invalidatePropertiesWasCalled:Boolean; override public function invalidateProperties():void { invalidatePropertiesWasCalled = true; super.invalidateProperties(); } }
  7. [Test] public function dummy_value_example():void { const UNUSED:String = “unused”; const

    service:ExampleService = new ExampleService(UNUSED); assertThat(service.isAvailable, isTrue()); }
  8. [Test] public function fake_example():void { var entityManager:IEntityManager = new FakeEntityManager();

    var entity:IEntity = new Entity(); var cmd:SaveEntityCommand = new SaveEntityCommand(); cmd.entityManager = entityManager; cmd.entity = entity; cmd.execute(); } class FakeEntityManager implements IEntityManager { public function save(entity:IEntity):Boolean { if (entity.isModified) { entity.updated(); return true; } return false; } }
  9. [Test] public function with_modified_entity_should_enable_saving():void { presenter.setEntity(new ModifiedEntityStub()); assertThat(presenter.saveEnabled, isTrue()); }

    [Test] public function with_unmodified_entity_should_disable_saving():void { presenter.setEntity(new UnmodifiedEntityStub()); assertThat(presenter.saveEnabled, isFalse()); } internal class ModifiedEntityStub extends Entity { override public function isModified():Boolean { return true; } } internal class UnmodifiedEntityStub extends Entity { override public function isModified():Boolean { return false; } }
  10. [Test] public function when_disabled_should_not_dispatch_events():void { target.dispatcher = new SpyingEventDispatcher(); target.disable();

    target.methodThatTriggersEvents(); assertThat(target.dispatcher.numEventsDispatched, equalTo(0)); } internal class SpyingEventDispatcher extends EventDispatcher { private var _numEventsDispatched:int = 0; public function get numEventsDispatched():int { return _numEventsDispatched } override public function dispatchEvent(event:Event):Boolean { _numEventsDispatched++; super.dispatchEvent(event); } }
  11. [Before] public function setup():void { user = new User(); user.username

    = "TEST_USERNAME"; user.password = "TEST_PASSWORD"; service = nice(SignInService); token = nice(AsyncToken); command = new SignInCommand(); command.service = service; command.event = new SignInEvent(user); } [Test] public function execute_should_sign_in_to_service():void { expect( service.signin(user) ).returns( token ); command.execute(); verify( service ); }
  12. package mockolate.examples { public class Example { public function method(...args):Result

    { return new Result(); } } } package mockolate.examples.generated { public class ExampleProxy extends Example { private var _interceptor:Interceptor public function ExampleProxy(interceptor:Interceptor) { _interceptor = interceptor; } override public function method(...args):Result { return _interceptor.intercept( new Invocation(this, "method", args, super.method)); } } }
  13. How Mock Objects Work Reflect Class Generate Proxy Forward Invocations

    Execute Specified Behaviour Verify Expected Behaviour
  14. package mockolate.examples { public class ExampleTest { [Rule] public var

    mocks:MockolateRule = new MockolateRule(); } }
  15. package mockolate.examples { public class ExampleTest { [Rule] public var

    mocks:MockolateRule = new MockolateRule(); [Mock] public var thing:IThing; } }
  16. package mockolate.kitchen { public class KettleTest { [Rule] public var

    mocks:MockolateRule = new MockolateRule(); public var kettle:Kettle; [Mock] public var heatingElement:HeatingElement; [Mock] public var thermostat:Thermostat; [Before] public function prepareKettle():void { kettle = new Kettle(heatingElement, thermostat); } } }
  17. package mockolate.kitchen { public class KettleTest { [Rule] public var

    mocks:MockolateRule; [Mock] public var heatingElement:HeatingElement; [Mock] public var thermostat:Thermostat; [Mock] public var dispatcher:EventDispatcher; } }
  18. package mockolate.kitchen { public class KettleTest { [Rule] public var

    mocks:MockolateRule; [Mock(type=”nice”)] public var heatingElement:HeatingElement; [Mock(type=”strict”)] public var thermostat:Thermostat; [Mock(type=”partial”)] public var dispatcher:EventDispatcher; } }
  19. [Before] public function setup():void { heatingElement = mocks.nice(HeatingElement); thermostat =

    mocks.strict(Thermostat); dispatcher = mocks.partial(EventDispatcher); }
  20. expect( object.call(arg) ) expect( object.getter ) expect( object.setter = value

    ) allow( object.call(arg) ) allow( object.getter ) allow( object.setter = value )
  21. [Test] public function switching_kettle_on_should_activate_heatingElement():void { mocks.expect(heatingElement.activate()).once(); kettle.switchOn(); } [Test] public

    function switching_kettle_on_should_activate_thermostat():void { mocks.expect(thermostat.activate()).once(); kettle.switchOn(); }
  22. [Test] public function switching_kettle_off_should_deactivate_heatingElement():void { mocks.expect(heatingElement.deactivate()).once(); kettle.switchOn(); kettle.switchOff(); } [Test]

    public function switching_kettle_off_should_deactivate_thermostat ():void { mocks.expect(thermostat.deactivate()).once(); kettle.switchOn(); kettle.switchOff(); }
  23. mock( object ).method(“call”).args(...args) mock( object ).getter(“property”) mock( object ).setter(“property”).arg(arg) mock(

    object ).methods(/regexp/).args(...args) mock( object ).getters(/regexp/) mock( object ).setters(/regexp/).arg(arg) stub( object ).method(“call”).args(...args) stub( object ).getter(“property”) stub( object ).setter(“property”).arg(arg) stub( object ).methods(/regexp/).args(...args) stub( object ).getters(/regexp/) stub( object ).setters(/regexp/).arg(arg)
  24. [Test] public function kettle_should_indicate_heatingElements_current_temperature():void { mocks.expect(heatingElement.currentTemperature) .returns(25, 63, 102); assertThat(kettle.currentTemperature,

    equalTo(25)); assertThat(kettle.currentTemperature, equalTo(63)); assertThat(kettle.currentTemperature, equalTo(102)); assertThat(kettle.currentTemperature, equalTo(102)); }
  25. [Rule] public var events:EventRule = new EventRule(); [Test(async)] public function

    toaster_should_eject_toast_when_timer_completes ():void { mocks.expect(timer.start()) .dispatches(new TimerEvent(TimerEvent.TIMER_COMPLETE)); events.from(toaster).hasType(ToastEvent.COMPLETE); toaster.switchOn(); } [Test(async)] public function toaster_should_eject_toast_when_timer_completes ():void { mocks.expect(timer.start()) .dispatches(new TimerEvent(TimerEvent.TIMER)) .dispatches(new TimerEvent(TimerEvent.TIMER), 10) .dispatches(new TimerEvent(TimerEvent.TIMER), 20) .dispatches(new TimerEvent(TimerEvent.TIMER_COMPLETE), 30); events.from(toaster).hasType(ToastEvent.COMPLETE); toaster.switchOn(); }
  26. [Test] public function blender_should_require_ingredients_added_in_correct_order():void { recipe = sequence("recipe"); expect( vessel.add(

    banana ) ).inSequence(recipe); expect( vessel.add( honey ) ).inSequence(recipe); expect( vessel.add( milk ) ).inSequence(recipe); expect( vessel.add( malt ) ).inSequence(recipe); blender = new Blender(motor, control, vessel); blender.add( banana, honey, milk, malt ); }
  27. [Test] public function blender_should_adjust_speed_of_motor_when_switched_on():void { power = states('power').startsAs('off'); expect( control.switchOn()

    ) .then( power.isStateOf('on') ).once(); expect( motor.adjustSpeed(1) ) .when( power.isNot('on') ).never(); expect( motor.adjustSpeed(1) ) .when( power.isStateOf('on') ).once(); expect( control.switchOff() ) .then( power.isStateOf('off') ).once(): expect( motor.adjustSpeed(0) ) .when( power.isStateOf('off') ).once(); blender = new Blender(motor, control); blender.switchOn(); }
  28. package mockolate.examples { public class ExampleTest { [Rule] public var

    mocks:MockolateRule = new MockolateRule(); } }
  29. package mockolate.examples { public class ExampleTest { [Rule] public var

    mocks:MockolateRule = new MockolateRule(); [Mock] public var thing:IThing; } }
  30. package mockolate.kitchen { public class KettleTest { [Rule] public var

    mocks:MockolateRule = new MockolateRule(); public var kettle:Kettle; [Mock] public var heatingElement:HeatingElement; [Mock] public var thermostat:Thermostat; [Before] public function prepareKettle():void { kettle = new Kettle(heatingElement, thermostat); } } }
  31. assertThat(object, received().method(“call”) ); assertThat(object, received().getter(“property”) ); assertThat(object, received().method(“property”) ); assertThat(object,

    received().methods(“call”) ); assertThat(object, received().getters(“property”) ); assertThat(object, received().methods(“property”) ); .args(...values) .never() .once() .twice() .thrice() .times(n) .atLeast(n)
  32. Mock Object principles Only mock types you own Be explicit

    about things that should not happen Specify as little as possible in a test Don’t use mocks to test boundary objects Don’t add behaviour Only mock your immediate neighbours Avoid too many mocks Create objects indirectly