I love it when the standards and philosophies I try to implement with my development team are validated by the experience of the team. Unfortunately, that validation usually occurs when the something bad happens. And I hate being the "I told you so", guy. It's hard to say "we should have done this" without being that guy, so I try to phrase things in terms of "let's make sure we do this in the future, and it will help prevent that from happening again". I don't always state things that way, though... have to keep working on that.
Background Story
Earlier this week, I did a small review session with my current project team, discussing the important of proper Model-View-Presenter setup and proper / complete unit tests for that MVP setup. I brought up an example of our applications login screen which has a username entry, password entry, and a drop down list of values based on the username entered. With these three simple input fields and two buttons on the screen (Login and Cancel buttons), can you guess how many unit tests I have for the presenter? ... twenty-three (23).
Why are there so many unit tests for such a simple screen? Because there is a lot of business logic and process involved in selecting a valid value from the drop down list, based on the username you specified. This logic includes handling for non-existent usernames, users with no values assigned to them, validating the value selected is ok for the user specified, and a few others.
The extent of my unit tests has covered every possible scenario that I could think of, including scenarios that I know my actual view implementation will not present. By handling for the cases that I know I will not even create in my view, I am accounting for the future development of the project, potential changes to requirements, and other developers coming along behind me and not knowing what should really be going on. I have safe-guarded the login screen from other developers (including myself) and from fringe-case broken code, that could potentially compromise our application.
Development Incident
Today, one of my team members asked me why I modified one of our entities to always instantiate sub-objects at default values, when the parent object is instantiated. I gave a brief description of how I was trying to follow a common principal in Domain Driven Design and Agile Development, where the aggregate object should never be instantiated in an invalid state.
After providing that brief description, it occurred to me that the reason for asking the question was because they were having a problem with the modifications that I made. As it turns out, my changes to always instantiate the sub-objects caused the add/edit screen for the parent object to break because the presenter for the screen is paying attention to whether or not the sub-objects were null, to decide whether or not the Save button was enabled.
To remedy the problem in the short term, we are rolling back the object changes so that the sub-objects are initially null. Long term, we will be discussing the need to provide a valid object state on instantiation and the idea that we should actively prevent null references instead of code for them.
Illustration of the important of Unit Testing completeness
The thought then occurred to me - if the presenter is relying on null values in the object to enable / disable functionality in the view, then there should be unit tests to show that the logic and functionality is working correctly. Since I was able to modify the entity without breaking any unit tests in the presenter, it follows that the presenter was not fully unit tested. Had the presenter been fully unit tested, the changes I made would have broken the unit tests and our automated build process would fail (we call non-passing/broken unit tests a build failure). I mentioned this to the team member, and I saw the light click on in his eyes... that moment of understanding why we should be unit testing so thoroughly.
In the future...
I'm sure we'll run into this again, in the future. I'm as guilty as anyone of not fully unit testing things... hopefully my team and I will continue to learn and grow, though, and we will continue to reduce the number of times that this situation occurs. The up-side, though, is that I will likely see more of the "aha!" moments in my team mebers. I love seeing that in my team members, even more than having it occur for me. If I can help that moment occur for my team, then I'm doing something right.