A stateful system changes persistent state instead of returning data directly. Its behavior depends on the state it receives and the state it commits afterward. section 6.4
Test a stateful operation by treating the changed state as its observable result:
- Initialize the system with a known state. section 6.4
- Execute the mutation with its input member. section 6.4
- Retrieve the resulting state and compare it with the expected value. section 6.4
- Test failure paths separately, such as rejecting an existing member. section 6.4
Adding a member
System.addMember receives a system state and a member, reads the previous state, delegates data manipulation to Library.addMember, and commits the next state. It returns no data; the test compares the committed state with the expected library state. section 6.4
Listing 6.21 The functions involved in the add member mutation
System.addMember = function(systemState, member) {
var previous = systemState.get();
var next = Library.addMember(previous, member);
systemState.commit(previous, next);
};
Library.addMember = function(library, member) {
var currentUserManagement = _.get(library, "userManagement");
var nextUserManagement = UserManagement.addMember(
currentUserManagement, member);
var nextLibrary = _.set(library, "userManagement", nextUserManagement);
return nextLibrary;
};
UserManagement.addMember = function(userManagement, member) {
var email = _.get(member, "email");
var infoPath = ["membersByEmail", email];
if(_.has(userManagement, infoPath)) {
throw "Member already exists.";
}
var nextUserManagement = _.set(userManagement,
infoPath,
member);
return nextUserManagement;
};
Trace the separation between the stateful shell and the data-manipulation functions that calculate the next state. section 6.4













