Why ‘Should Attach View To Presenter’ Is An Invalid Unit Test / Observation.

I’ve written a lot of specification tests like this in the last three years, from a UI / Workflow perspective, with Model-View-Presenter as my core UI architecture:

[TestFixture]
public class When_starting_some_process()
{
 
 IMyView view;
 MyPresenter presenter;
 
 [Setup]
 public void Setup()
 {
   //...setup code and execute stuff for the test here
   view = MockRepository.GenerateMock<IMyView>();
   presenter = new MyPresenter(view);
 
   presenter.StartSomeProcess();
 } 
 
 [Test]
 public void Should_attach_the_view_to_the_presenter()
 {
   presenter.View.ShouldNotBeNull();
 }
 
 [Test]
 public void Should_show_something()
 {
   view.AssertWasCalled(v => v.ShowSomething(something));
 }
 
}

The Devil In These Details

I had one of those ‘aha!’ moments yesterday where several of my nagging suspicions and annoyances at writing specification tests like this example finally gelled into a coherent understanding. That understanding is easily stated by saying that the test, “Should_attach_the_view_to_the_presenter” is invalid and should never be written. There are a number of reasons for this.

  1. In practicing BDD, the technical jargon that is leaking into the test is irrelevant to the real value that is intended with this specification
  2. In practicing any form of TDD, the implementation detail of attaching a view to a presenter creates a brittle test – I care about the API and how the system really works, not a very technical, implementation detail like this.
  3. Exposing the “View” property of the Presenter object is a violation of encapsulation and an ‘over-intimate’ smell. My test has far too much fine detail, granular knowledge of what’s going on behind the scenes, to really be of any practical value
  4. Finally – and possibly outweighing all other reasons combined – it’s simply not necessary.

Look at the second test: “Should_show_something”. It’s actually using the view. Presumably, the “StartSomeProcess” method on the presenter is going to call a method on the view – that’s why we are asserting that the method on the view was called. If this is true, then it can be safely assumed that not having a view attached to the presenter would throw a null reference exception when trying to call that method on the view.

If not having the view attached to the presenter results in a null reference exception for the other test, then we have a valid reason for that test to fail. We certainly can’t say that the view’s method was called when the view is null. Therefore, testing to ensure that we have a view attached to the presenter is a duplication of effort. We’re only proving what we have already proved transitively, via another test.

Beauty And Meaning In Simplicity

Assuming that this is all true, we can remove that test entirely. Our specification now looks like this:

[TestFixture]
public class When_starting_some_process()
{
 
 IMyView view;
 MyPresenter presenter;
 
 [Setup]
 public void Setup()
 {
   //...setup code and execute stuff for the test here
   view = MockRepository.GenerateMock<IMyView>();
   presenter = new MyPresenter(view);
 
   presenter.StartSomeProcess();
 }
 
 [Test]
 public void Should_show_something()
 {
   view.AssertWasCalled(v => v.ShowSomething(something));
 }
 
}

It’s one less test to deal with, yet is as expressive and meaningful. In fact, I would say it is more meaningful because we have avoided all of the problems I listed. I’m reminded of a quote by Alan Cooper:

“No matter how beautiful, no matter how cool your interface, it would be better if there were less of it.”

Although I think he was specifically addressing User interfaces in this quote, it is applicable to all interfaces – programmatic, user, etc. Simplicity and subtleness is the key. I know I’m not the first person to talk about this problem, why it’s a problem, or the solution. I’m only claiming that I finally had that ‘aha!’ moment and realized why so many others have talked about this before.


Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs SignalLeaf.com - the amazingly awesome podcast audio hosting service that everyone should be using, and WatchMeCode.net where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in .NET, Analysis and Design, Behavior Driven Development, C#, Model-View-Presenter, Principles and Patterns, Unit Testing. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://huntjason.spaces.live.com JH

    *applause*

    Thank you, Derick, for this!

  • http://tunatoksoz.com Tuna Toksoz

    I believe the first one is more readable. It tells you something about how the things should done. When it fails, you know what the null object is.

  • http://www.lostechies.com/members/derick.bailey/default.aspx derick.bailey

    @JH – Thanks!

    @Tuna,

    I understand that position, too. I held the same opinion for the last few years, basically. I’m not going to say that either one of our opinions is wrong – it really comes down to your expectations of what the unit tests tell you. At this point, I don’t see that test telling me anything i don’t know. when i get a null reference exception in the other test, the stack trace that’s output by my test runner tells me what line of code is null, i double click the error message and it takes me right to the line of code.

  • http://scottbellware.com Scott Bellware

    Before you loose the understanding to time, can you observe yourself in the immediate past from the place where you are now and try to understand what it was that was keeping this understanding hidden?

  • http://www.lostechies.com/members/derick.bailey/default.aspx derick.bailey

    @Scott,

    Wow – that’s a powerful question. I’m not sure I can, with any clarity, though.

    This may just be rambling…. I keep coming back to Plato’s Forms and the story of The Cave in my head. It’s as if I suddenly recognize that the light behind us was a fire in the cave, casting shadows on the wall in front of us, with the ability to see the shadows for what they are.

    I’ve heard others, yourself included, talk about how we need to be moving away from tests that over-specify and deal with implementation detail, and move towards tests that deal with the business need and behavior of the system under test. i always ‘believed’ this and thought that I was moving toward this. however, i always thought that it was necessary to include a technical detail such as attaching the presenter to the view. after all, how else would you know that it was there? … after the ‘aha!’ moment, and the clarity that I’ve attempted to describe above, when i look back on how well I previously thought I was doing, I realize the fallacy and limitations of what I was doing.

    I think I can see why you talk about our own attachments, from this experience. I was very clearly attached to the idea that i need to test the view being held by the presenter.

    … i’m not sure how else to express the difference, really. i can’t seem to find the language that expresses it correctly.

  • http://scottbellware.com Scott Bellware

    Yes, it’s all about attachment.

    The nature of attachment is that the moment we have one, we risk not being aware that we have it because it becomes the lens through which we perceive the world.

    We don’t see the lens unless we are always looking for the lens and practicing looking for the lens. The reason to look for the lens is that the purpose of a lens is to bend the truth and the best way to do something is inevitably the true way to do it.

    To the mind, the truth looks like the truth whether it’s bent by a lens or not. It’s only when we become aware of the lens that we can take it down and see the world without it.

    Attachment has no inherent staying power on its own. The only thing keeping it in place is vanity.

    When I believe that my perception can’t possibly be distorted, then I stop looking for the next lens. When I believe that I’m naturally imbued with the power to directly perceive without illusion, I’m inevitably perceiving through delusion.

    If I do this for long enough, I become self-identified. I stop in my place. When I identify, I seek social circles that justify my identity, and these social circles end up calcifying my attachment, and this turns into a vicious circle of stasis and decay.

    Attachment, identification, and vanity are always making us progress dramatically slower than our potential. They’re the source of our ignorance.

    I’m always an authority in the moment, but I’m looking for the flaw in my perception in every moment. I’m ready to give up on even my most deeply-held beliefs because I know that my perception is always distorted by attachment.

    Consequently, the more I practice detachment, the more I actually see and the greater the risk I have of becoming attached to what I see and my beliefs about the subjects of my authority. I learn to trust my instincts and intuition much more, but these things are feelings and are just as susceptible to vanity.

    By continuing to sabotage my own attachments and identification I can slowly but surely learn to see the previously-unrecognized assumptions that distort my perceptions and lock me in to unquestioned habits.

    Authority is the most dangerous result of knowledge. It creates celebrity and vanity feeds off of it.

    Celebrity is as inevitable as attachment and identification. Keeping it from keeping us from the truth help us to not become even greater obstructions to the people who listen to us. It’s a responsibility.

    I attack people when their vanity starts to outpace their learning. It’s a matter of introducing psychic shock because shock is the only thing that induces the moment of clarity that see the attachment itself as opposed to seeing through it.

    Who am I to believe himself entitled to do this? Am I vane? Of course I am, but I’m also saddened by the attachments that many of my gang have fallen prey to over the past few years as they have given in to the stasis of celebrity and have forgotten about the time when they would daily question the assumptions of the world around them.

    And there’s the crux: it’s easy to question the world around you when it naturally doesn’t jive with your current instinctive values. The real work is all about questioning the truth of your own values – especially once you find yourself in a circle of people who share and reinforce those values.

    Ironically, a community of rebels will become the status quo faster because they’re a community. If their point of view becomes predominant, they continue to believe that they are progressive and can’t understand why others would think of them as the new status quo.

    This is the story of alt.net, going all the way back to the time before it was named to now when it has lost its momentum and is transitioning prematurely to stasis.

    The absolute most important thing about all of this is that there’s something you’re doing right now that is the ignorant thing you’ll realize at some point in the future. If we’re not actively chasing these things down and sharpening our perspectives, then we leave the pace of realization up to pure change, waiting for some stray gamma particle to accidentally flip some neural bit.

    Much better to have one part of the mind acting on what we know while another part is actively observing our conclusions and looking for the flaw. I know that everything I do is flawed and I’m actively looking for it in everything.

    If we’re not doing this, we’re just going to end up attached and identified and stuck in a cargo cult that we’re not even aware of. If we are doing it, the world quickly becomes a very irritating place to live, pushing the imperative for detachment and disidentification even further.

    So, while you recognize value in Kanban, what’s to say that your particular perception of that value isn’t distorted, and that the gravity of your celebrity isn’t the lens that might be distorting the perception of your team?

    Sooner or later we have to make improvements. The important thing with anything new is to have one part doing and one part looking for the inevitable imperceptible flaw. This keeps me flowing while simultaneously preparing me to see and accept the bonehead that I continue to become. And after doing it for a couple of decades, it’s helping me to see the flaws often much earlier than my compadres – at least in my areas of interest and operation.

  • Anonymous

    @Bellware in the movie “A Beautiful Mind”, the main character has a scene where they are in a shed with pictures and newspaper clippings and red yard attached with push pins.

  • http://tunatoksoz.com Tuna Toksoz

    @derick
    Indeed!

  • Michael A. Smith

    @Scott It is very difficult to follow a post of that magnitude. :P

    In response to what Scott said, I have found myself, at times, attached to looking for the lens.

    Scott’s post reminded me that we have a tendency to identify more than one solution to technical problems and then proclaim that these many solutions exist because other factors make them situational. I think we develop this composite truth because we are pragmatic. For example, in Plato’s “Allegory of the Cave”, even if the observers of the shadows were pragmatic, their composite truth would/could still only be a psuedo-truth as their peceptions are inherently limited. This might also suggest that we shouldn’t be attached to seeking the truth as well.

    As for the truth, is it a gift or something earned through effort? Or both?

    Thanks Scott, for inspiring us to improve ourselves.

  • http://michael.smith Michael A. Smith

    @Derick I’ve been mulling your post over in my head all day and I believe I’ve finally grasped a few things about TDD/BDD that have been bugging me as well. Thanks so much or this post :)

  • http://sbiefeld.com sean biefeld

    So what if I am testing functionality like:

    int.TryParse(View.AssessmentMedicationTreatmentId, out id)

    I cannot think of a good way to write BDD style tests for the code above without using technical jargon in the naming. I want to write tests for three main scenarios, null, empty string, and non-numeric string.

    when_viewing_record_of_waste_with_a_null_medication_treatment_id
    – should_show_the_user_a_validation_message

    when_viewing_record_of_waste_with_an_empty_medication_treatment_id
    – should_show_the_user_a_validation_message

    when_viewing_record_of_waste_with_an_invalid_medication_treatment_id
    – should_show_the_user_a_validation_message

  • http://scottbellware.com Scott Bellware

    Sean,

    Can you provide more context than a single line of code?

  • http://sbiefeld.com sean biefeld

    Yes I can provide more context :P

    I am working on a record of waste form for the disposal of pain medications. The data being recorded on the form is a residual amount and disposal date. The data being displayed is patient demographics, episode information, assessment information and the record of waste information.

    The system tracks multiple assessments for a patient, there are medications associated with those assessments. A record of waste has to be filled out for those medications when they are disposed.

    When initializing the record of waste form, the Assessment Medication Id is coming to the view in the form of a query string. I am validating that Id and loading the Assessment Medication out of the database. Once loaded I am telling the view to display the pertinent assessment/record of waste information.

    My specification and observations for a valid Id:

    when_viewing_record_of_waste_with_a_valid_medication_treatment
    -should_load_assessment_medication_treatment
    -should_load_episode_display_info
    -should_show_the_record_of_waste_detail_information
    -should_show_episode_information
    -should_show_patient_information

    The Id validation method:
    private bool AssessmentMedTreatmentIdIsValid()
    {
    int id;

    bool isValid = int.TryParse(View.AssessmentMedTreatmentId, out id);

    if(isValid)
    AssessmentMedTreatmentId = id;

    return isValid;
    }