mardi 3 mars 2015

How to unit test a method whose side effect is to call other method?

Here is my example:



void doneWithCurrentState(State state) {
switch (state) {
case State.Normal:
// this method is never actually called with State.Normal
break;
case State.Editing:
controller.updateViewState(State.Normal);
database.updateObjectWithDetails(controller.getObjectDetailsFromViews())
break;
case State.Focus:
controller.updateViewState(State.Editing);
break;
}
}


My controller calls the doneWithCurrentState when a specific button is pressed. The states are different positions on screen that the views for that controller can assume.


If the current state is Normal, the button will be hidden.


If the button is pressed with the current state as Editing, the doneWithCurrentState method (I say method because it is actually inside a class ``) will be called and it should change the controller's views state to Normal and update the Object in the database using the ObjectDetails (which is just a struct with data that will be used to update the Object) that should be retrieved from the controller's views (i.e., text fields, checkboxes, etc).


If the button is pressed with the current state as Focus, it should just send back to the Editing state.


I am unit testing it like this:



void testDoneWithCurrentStateEditing() {
mockController.objectDetails = ...;

myClass.doneWithCurrentState(State.Editing);

AssertEqual(mockController.viewState, State.Normal, "controller state should change to Normal");

AssertTrue(mockDatabase.updateObjectWithDetailsWasCalled, "updateObjectWithDetails should be called");
AssertEqual(mockDatabase.updatedWithObjectDetail, mockController.objectDetails, "database should be updated with corresponding objectDetails");
}

void testDoneWithCurrentStateFocus() {
myClass.doneWithCurrentState(State.Focus);

AssertEqual(mockController.viewState, State.Editing, "controller state should change to Editing");

AssertFalse(mockDatabase.updateObjectWithDetailsWasCalled, "updateObjectWithDetails should not be called");
}


But it seems wrong, it seems like I'm asserting a method call is made and then I'm making the call... it's just like asserting setter and getter methods.


What would be the right way of testing that doneWithCurrentState method? As part of the answer, I do accept something like "first you should refactor the method to better separate these concerns...".


Thank you.


Aucun commentaire:

Enregistrer un commentaire