Question

I'm looking for some clarification regarding Arrange/Act/Assert, which I'm implementing in my development process as Given-When-Then. I try to stick to the concept, but I'm finding that during certain events (particularly user input), I have to reconsider an "Act" action as an "Arrange" action in order for it to properly be captured in the unit test. I'm using Moq as my mocking framework here.

For instance: In my project, the focal point of the code is an image provided by the user. A feature exists where the user can choose an image, but if an image is already present, it will query the user if they want to replace the active image, or cancel the action and keep the active image. I feel that the proper way of writing this particular scenario would be:

Given a workspace with an image already present
When the user requests a new image
And the user chooses to replace the active image
Then the program should replace the image

Testwise, it looks something like this:

mockModel.SetupProperty(m => m.Image, new Bitmap(100, 100));  // Given
mockView.Raise(v => v.UserRequestsNewImage += null);          // When
mockMBox.Setup(mb => mb.ViewResult).Returns(ViewResult.OK);   // And
mockView.Verify(v => v.OpenAddImageFileDialog(), Times.Once); // Then

Codewise, in my presenter, it looks something like this:

private void view_UserRequestsNewImage()
{
  if (model.Image != null)
  {
    mbox.ShowDialog();

    if (mbox.ViewResult == ViewResult.Cancel)
      return;
  }

  view.OpenAddImageFileDialog();
}

But this fails, because the Message Box's Setup occurs after the View's Raise is called. As such, I need to move the Setup before it (and using Setup makes it feel like an "Arrange" setup anyway):

Given a workspace with an image already present
And the user chooses to replace the active image
When the user requests a new image
Then the program should replace the image

But now, my scenario feels out of order, and that it doesn't flow correctly. I feel that the user's choice to replace the image (the Setup), since it occurs after the user's choice to add a new image (the Raise), should be part of the Act step, but in order for it to properly mock, I need to put it in the Arrange step.

Am I using the mocking framework wrong here? Is there a better way to do this? Or am I fretting unrealistically about where the user input step should be located in the Given-When-Then setup?

Thanks in advance.

Was it helpful?

Solution

"When the user requests a new image" that user has to choose to replace the current image.

So you could re-write the "Given, When, Then" to read:

  • Given a workspace with an image already present
  • When the user chooses to replace the active image
  • Then the program should replace the image

i.e. omit the "When" which states that "the user requests a new image", as they have to to this anyway when replacing the current image.

Also I'd ditch the comments (a code smell, though granted there are not many of them!) and put these test steps into small methods like so:

void GivenImageAlreadyPresent()
{
 mockModel.SetupProperty(m => m.Image, new Bitmap(100, 100));  
}

void WhenActiveImageReplaced()
{
 mockMBox.Setup(mb => mb.ViewResult).Returns(ViewResult.OK);   
 mockView.Raise(v => v.UserRequestsNewImage += null);          
}

void ThenImageShouldBeReplaced()
{
 mockView.Verify(v => v.OpenAddImageFileDialog(), Times.Once);
}

void Test()
{
 GivenImageAlreadyPresent();
 WhenActiveImageReplaced();
 ThenImageShouldBeReplaced();
}

This makes the actually test read better (i.e. its now self-documenting) and it'll enable to re-use the steps if need be.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top