Question

I am learning robotlegs framework, but this question is also I think of general nature.

I have a Mediator class that listens for event on a button in View and on that event it dispatches a signal containing VO which contains properities from two TextField objects in View.

Below is mediator class.

button is a private variable that only has getter and no setter in View.

My Question is, how would I unit test this class? 1. to check if event comes that Signal is being dispatched... 2. when signal is dispatched, that it contains correct VO

I know that I need to use Mock, and I am using mockolate, but i am spinning in circle, because i don't know how to mock a dispatched event from a button from view class?

Thanks for help

        public class LoginFormMediator extends Mediator {

            //---------------------------------------------------------------
            //  Public variables
            //---------------------------------------------------------------



            [Inject]
            public var view:LoginFormView;
            [Inject]
            public var authorizationSignal:AuthorizationSignal;


            //---------------------------------------------------------------
            //  Public Functions
            //---------------------------------------------------------------

            override public function initialize():void
            {
                view.button.addEventListener(MouseEvent.CLICK,onLogin,false,0,true);

            }



            //---------------------------------------------------------------
            //  Private methods
            //---------------------------------------------------------------
            private function onLogin(event:MouseEvent):void {
                var userInfo:UserInfo = new UserInfo(view.usernameField.text,view.passwordField.text);
                authorizationSignal.dispatch(userInfo);

            }

        }
        }
Was it helpful?

Solution

There's a few possibilities:

1/ don't expose the button and let the mediator listen to it directly. The view should dispatch a specific, concrete event to which the mediator is listening and preferably this describes user intention, not user action. E.g: let the view dispatch a LoginFormViewEvent.LOGIN_REQUESTED or maybe a LoginFormViewEvent.CREDENTIALS_PROVIDED event. The reason why this is better is that it doesn't tie your mediator to a specific implementation of your view. For instance, maybe later on you want to add some kind of validation rule that needs to be run before the credentials are dispatched. If you listen to the button directly you'll either be writing the validation logic into the mediator, which is a definite no-no or you'll need to refactor your view.

A mediators job is to mediate between a view and the system, nothing more. It doesn't need to know what UI elements are in the view, just pass data from the view to the system and vice versa.

2/ Another possibility is to let the mediator pass the system-wide signal to the view, which does the dispatching and VO population.

//mediator
[Inject]
public var view:LoginFormView;
[Inject]
public var authorizationSignal:AuthorizationSignal;

override public function initialize():void{
    view.authorizationSignal = authorizationSignal;
}

//view
public var authorizationSignal : ISignal;

public function init():void{
    button.addEventlistener( MouseEvent.CLICK, button_clickHandler );
}

private function button_clickHandler( event : MouseEvent ) : void{
    var vo : UserInfo = new UserInfo( usernameField.text, passwordField.text);
    authorizationSignal.dispatch( vo );
}

I tend to make the signal conditionally instantiated and generic, to make the view more easily reusable. Like this:

//view
private var _authorizationSignal : ISignal;
public function set authorizationSignal( value : ISignal ) : void{
    _authorizationSignal = value;
}
public function get authorizationSignal() : ISignal{
    return _authorizationSignal ||= new Signal();
}

Then the signal injection is optional and the view provides a default signal instance.

3/ Or if you choose to stick to your original approach, you can mock the button the normal mockolate way. Let your view implement an interface where a getter for the button is declared. Map your mediator to the interface (which is good practice anyway) instead of the concrete view type. This way you can assign a mocked button to it in the test class, yet have the button encapsulated facing the mediator.

Then, to have the mocked button dispatch the event:

[Mock]
public var mockButton : Button;

//in setup 
view.button = mockButton

//in test
mockButton.dispatch( new MouseEvent( MouseEvent.CLICK ) );
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top