In the prior posts, we discussed a Passive View for the purposes of testability and also talked about using an Event Bus to decouple one UI component from another. Remember that the ContactDetailPresenter functionally will be responsible for 1) displaying a selected Contact and 2) enabling a Contact to be updated. Given the design we used to build out the presenter, we should now be able to test, in isolation, that it correctly does both of those things. “In isolation” means that we want to test that the ContactDetailPresenter does what it’s supposed to do without having using a ContactListPresenter in the test. Since this is an automated, non-interactive test and we don’t have an actual browser, it will be important that we can mock the ContactDetailView. We threw around the word “mock” loosely before, but now that we’re actually writing tests, we need to be more clear about what this means and how to do it. For the tests written in this example, we will use EasyMock and that library will be implementing many methods you see in the tests such as createMock(), expect(), andReturn(), etc. It is not the scope of the post to describe EasyMock in detail, but know that having a good approach to mocking objects is a critically important aspect to writing/maintaining a solid automated test suite.
The first test validates that the ContactDetailPresenter will send a selected Contact’s first name to the ContactDetailView. The test starts out by 1) setting up its expectations that the view will receive a first name. Then 2) simulates a Contact-selection by posting a ContactSelectedEvent to the event bus and lastly 3) verifies that the View did, in fact, have the selected Contact’s first name applied to it. Here is the test:
public void testContactSelected (){
EventBus eventBus = new EventBusImpl();
String firstName = "mockFirstName";
// set up a Contact with a particular first name
Contact contact = createMock(Contact.class);
expect(contact.getFirstName()).andReturn(firstName);
// 1) set up expectation that view should be set with the first name
ContactDetailView view = createMock(ContactDetailView.class);
HasChangeHandlers mockHasChangeHandlers = createMock(HasChangeHandlers.class);
expect(view.setFirstName(firstName)).andReturn(mockHasChangeHandlers);
replay(view, contact);
ContactDetailPresenter presenter = new ContactDetailPresenter(view, eventBus);
// 2) now fire event and ensure that view is set with first name
ContactSelectedEvent contactSelected = new ContactSelectedEvent(contact);
eventBus.fireEvent(contactSelected);
// 3) verify the View had the Contact’s first name set on it
verify(view);
}
The next test validates that a user updating the first name in the Contact Detail UI will cause the ContactDetailPresenter to 1) change the first name of the Contact in the Model and 2) emit an event that the Contact was updated. To accomplish this, the test will first mock up the presenter’s dependencies to behave as needed for the test. Next, the test will simulate the first name change. Lastly, the test will verify its expectations.
public void testContactUpdated(){
String firstNameBefore = "mockFirstNameBefore";
final String firstNameAfter = "mockFirstNameAfter";
// mocks up view to have a TextInput that our test can control
ContactDetailView view = createMock(ContactDetailView.class);
final TextInput firstNameInputMock = new TextInputMock();
expect(view.setFirstName(firstNameBefore)).andReturn(firstNameInputMock);
/*
* set up a mock Contact to accept a firstName on setFirstname and
* return that same first name on getFirstName.
*/
Contact contact = createMock(Contact.class);
final CapturefirstNameCapturer = new Capture ();
contact.setFirstName(capture(firstNameCapturer));
expectLastCall().anyTimes();
expect(contact.getFirstName()).andAnswer(new IAnswer() {
public String answer() throws Throwable {
return firstNameCapturer.getValue();
}
}).anyTimes();
replay(contact, view);
EventBus eventBus = new EventBusImpl();
// add handler to event bus to listen for ContactUpdatedEvents
final ContactUpdatedEvent[] updatedEvent = {null};
eventBus.addHandler(ContactUpdatedEvent.TYPE,
new ContactUpdatedEvent.ContactUpdatedEventHandler() {
public void handleEvent(ContactUpdatedEvent contactUpdatedEvent) {
updatedEvent[0] = contactUpdatedEvent;
}
});
// wire up presenter with its dependencies
ContactDetailPresenter presenter = new ContactDetailPresenter(view, eventBus);
contact.setFirstName(firstNameBefore);
presenter.setContact(contact);
// simulate the first name change on the TextInput
firstNameInputMock.setText(firstNameAfter);
// verify expectations
assertNotNull("The ContactUpdatedEvent should have been emitted when the text was changed on the input", updatedEvent[0]);
assertEquals("The name of the Contact should have been changed to the new name",
firstNameAfter,
updatedEvent[0].getContact().getFirstName());
}
This is extremely powerful. We’ve tested some core aspects of our interactive web application without actually having a user interface written or even established. We have not yet built anything that resembles HTML. Given this, we can really start seeing the flexibility of this design. Since most of the Contact List UI Component works and is testable with no View, it really illustrates how little we are locked in to a particular UI layout.
In this post we looked at techniques for testing a Presenter. This is a critical component to test since it contains a lot of UI logic and, due to our MVP design pattern, it is testable.
This comment has been removed by the author.
ReplyDeleteThis is a terrific article, and that I would really like additional info if you have got any. I’m fascinated with this subject and your post has been one among the simplest I actually have read.
ReplyDeleteJava training in Chennai | Java training in Bangalore
Java online training | Java training in Pune
You’ve written a really great article here. Your writing style makes this material easy to understand.. I agree with some of the many points you have made. Thank you for this is real thought-provoking content
ReplyDeleteData Science training in kalyan nagar | Data Science training in OMR
Data Science training in chennai | Data science training in velachery
Data science training in tambaram | Data science training in jaya nagar
Impressive. Your story always bring hope and new energy. Keep up the good work.
ReplyDeletedevops online training
aws online training
data science with python online training
data science online training
rpa online training
I’m planning to start my blog soon, but I’m a little lost on everything. Would you suggest starting with a free platform like Word Press or go for a paid option? There are so many choices out there that I’m completely confused.nice blog.
ReplyDeleteAi & Artificial Intelligence Course in Chennai
PHP Training in Chennai
Ethical Hacking Course in Chennai Blue Prism Training in Chennai
UiPath Training in Chennai
This is an awesome post.Really very informative and creative contents. These concept is a good way to enhance the knowledge.I like it
ReplyDeleteJava training in Chennai
Java Online training in Chennai
Java Course in Chennai
Best JAVA Training Institutes in Chennai
Java training in Bangalore
Java training in Hyderabad
Java Training in Coimbatore
Java Training
Java Online Training
Thank you so much for sharing these amazing tips. I must say you are an incredible writer, I love the way that you describe the things. Please keep sharing.
ReplyDeletedata science training in chennai
data science training in velachery
android training in chennai
android training in velachery
devops training in chennai
devops training in velachery
artificial intelligence training in chennai
artificial intelligence training in velachery
Pretty article! I found some useful information in your blog, it was awesome to read, thanks for sharing this great content to my vision, keep sharing.
ReplyDeletehardware and networking training in chennai
hardware and networking training in porur
xamarin training in chennai
xamarin training in porur
ios training in chennai
ios training in porur
iot training in chennai
iot training in porur