Closed ghost closed 14 years ago
Yes you can mock a ChannelSet.
However in the current implementation of your LoginDelegate there are some issues.
1) the ChannelSet instance it uses is not public, it is retrieved from a ServiceLocator-type Object, and 2) the ServerConfig.getChannelSet() method appears to be static and cannot be mocked, 3) what/where is authenticationService on the LoginDelegate?
Issues 2, 3 can be resolved by using Dependency Injection. Instead of the LoginDelegate asking ServerConfig which ChannelSet it should use, you instead give it the instance when it is constructed.
Change LoginDelegate to have a public var for the ChannelSet that can be injected.
// LoginDelegate.as
package deshartman
{
import mx.messaging.ChannelSet;
import mx.rpc.AsyncToken;
public class LoginDelegate
{
public var channelSet:ChannelSet;
public function LoginDelegate()
{
super();
}
public function login(username:String, password:String):AsyncToken
{
return channelSet.login(username, password);
}
}
}
And then when you construct the Services, Delegates, etc
var authenticationService:AuthenticationService = new AuthenticationService();
var loginDelegate:LoginDelegate = new LoginDelegate();
loginDelegate.channelSet = ServerConfig.getChannelSet(authenticationService.destination);
This decouples LoginDelegate from ServerConfig, and allows you to inject a mock ChannelSet when testing.
With the above changes it is now much easier to mock the ChannelSet.
package deshartman
{
import mockolate.runner.MockolateRunner; MockolateRunner;
import mx.messaging.ChannelSet;
import org.hamcrest.object.equalTo;
[RunWith("mockolate.runner.MockolateRunner")]
public class LoginDelegateTest
{
public var delegate:LoginDelegate;
[Mock]
public var channelSet:ChannelSet;
[Before]
public function setup():void
{
delegate = new LoginDelegate();
delegate.channelSet = channelSet;
}
[Test]
public function loginShouldCallServiceWithUsernameAndPasswordAndReturnAsyncToken():void
{
var username:String = "USERNAME";
var password:String = "PASSWORD";
var token:AsyncToken = new AsyncToken();
mock(channelSet).method("login").args(username, password).returns(token)
assertThat(delegate.login(username, password), equalTo(token));
}
}
}
If you need to mock the result or fault from the ChannelSet you can do the following:
[Test(async)]
public function loginShouldSucceed():void
{
var username:String = "USERNAME";
var password:String = "PASSWORD";
var resultData:String = "OK";
var token:AsyncToken = new AsyncToken();
var resultEvent:ResultEvent = new ResultEvent(ResultEvent.RESULT, false, false, resultData, token);
mock(channelSet).method("login").args(username, password)
.returns(token)
.answers(new ResultAnswer(token, resultEvent))
.dispatches(resultEvent);
Async.proceedOnEvent(this, channelSet, ResultEvent.RESULT);
delegate.login(username, password);
}
[Test(async)]
public function loginMayFail():void
{
var username:String = "USERNAME";
var password:String = "PASSWORD";
var faultCode:String = "DENIED";
var faultString:String = "Bad username or password";
var faultDetail:String = "";
var token:AsyncToken = new AsyncToken();
var faultEvent:FaultEvent = new FaultEvent(FaultEvent.FAULT, false, false, new Fault(faultCode, faultString, faultDetail), token);
mock(channelSet).method("login").args(username, password)
.returns(token)
.answers(new FaultAnswer(token, faultEvent))
.dispatches(faultEvent);
Async.proceedOnEvent(this, channelSet, FaultEvent.FAULT);
delegate.login(username, password);
}
HTH
Drew,
Thanks for the explanation. Helps understand the mocking even better. One part I am not clear on:
new ResultAnswer(token, resultEvent))
Not sure what this is and I cannot find this in Flex
Thanks Des
ResultAnswer
and FaultAnswer
are new additions to Mockolate to make working with AsyncToken
easier. They call the result or fault responders of the AsyncToken. If you don't have them in your clone of Mockolate you might need to do a git pull
or git fetch
to get the latest.
If you have a look at HTTPServiceDecorator
in the mockolate.decorations.rpc
package, you can see in the result()
and fault()
methods how the token, result or fault, is managed.
HTH
Drew
That was the problem. I pulled the latest and I can now see ResultAnswer. My test works, except that I had to remove the ".dispatches(resultEvent);" part of the mock. It keeps failing with
Error: Mockolate target is not an IEventDispatcher, target: [object LoginDelegateAD6451211F1E599AFD7750EE2CD7054A1F78770D]
Not sure why.
Thanks for your help again. Des
Its just saying that the LoginDelegate class isn't an IEventDispatcher, so it doesn't support using dispatchesEvent()
. Safe to take that call out if you don't need it to dispatch any events.
cheers, Drew
Drew
Thanks for the clarification. I have all my Mocks working now!
Des
Hi Drew
Is there anyway to mock a channelset.login and logout? I have the following code in my delegate called from my controller, which I would like to confirm works. I tried Brian LeGross's RPCStubs, but he confirmed that he has not yet implemented channelsets, so just wondering if this is something you deal with?
Thanks Des
Controller
public class LoginController extends AbstractController { [Inject] // Wire in the model public var loginModel:LoginModel;
}
Delegate
public class LoginDelegate {
}