views:

279

answers:

6

Hi folks, i have a method that does takes in a object and saves it to the database. But, before i save the object, i do the following...

(psuedo code)

if (IsAuthenticated)
{
   foo.UserId = AuthenticatedUser.Id;
}
else
{
   foo.AnonEmail = "Jon@World-Domination";
   foo.AnonName = "Jon Skeet";
}

try
{
    _fooService.Save(foo);
}
catch
{
    // Some view, with error stuff now added to 
    return View(...); ViewData.ModelState.
}

// all good, redirect to the proper next view.
return RedirectToAction(...);

That code works fine, but i'm not sure how to write the two unit tests for a success. a) User is authenticated with valid data b) User is not authentiated with valid data.

The reason why i'm not sure what to do is, is that both scenario return the same RedirectToAction(..) view object. So i can successfully test that .. but it doesn't tell me if the object saved contains the authenticated user id or the anon info. It's like i want the first unit test to say

  • moq up an authenticated user
  • call method
  • test if result is RedirectToActionView
  • test if the foo object that was persisted contains the moq'd user id.

thoughts?

Update

The common suggestion is that i mock the fooService. I'm currently using Dependency Injection and Moq, so could somone show me how i would use Moq? I'm not sure how the DI is important here, though ???

+3  A: 

I would mock up the _fooService object, and test what it receives as part of your test. That way your surrounding code remains the same and is untouched, and by checking what _fooService receives, you can assert whether the behaviour is as expected. The return object is not of interest in this case.

How do you mock your _fooService ? You can either implement your own 'test' version (adhering to the same interface as the real world version), or using a mocking framework. Whichever approach you use, your code above needs to be configured with a given implementation of the _fooService (usually on construction - see dependency injection for more info on how this may work)

Brian Agnew
Currently i'm using structuremap for my DI and moq for mocking. I'm hardly understand how to use moq very well - could u please update your answer to include some moq code samples, about how to do this?
Pure.Krome
I've not use moq, I'm afraid. I've come at this from a Java perspective, so I've only experience of mocking using Java tools. However you *can* easily put together 2 versions of _fooService. One doing the real work, and one that just checks the results passed to it. Does that help ?
Brian Agnew
sure does and i already have this. I have fake repositories and real repositories. As for the service, i don't fake those. The DI determines which repository to use. I still need someone to show me how to use MOQ to verify the result getting passed through.
Pure.Krome
+1  A: 

You might mock _fooService.Save(foo) and inspect the supplied foo.

Daniel Brückner
Can u please check my comment in Brian's answer, please?
Pure.Krome
A: 

you still have a reference to your object. At the end of your unit test, couldn't you just assert what the value was foo.AnonEmail or UserId?

Unit tests should not touch an external source, (that's an integration test) so if you go that route you should mock your datasource and then test through your mock.

Khalid Abuhakmeh
A: 

Do you have access to foo in the test? I'm assuming it's a field on the class. Is there a public getter? If not you may have to use Reflection (I assume that's available in asp.net, but I'm not too familiar with it)

Davy8
A: 

You want to use the DI to get the correct implementation of fooservice into your object, so at testing time you can do this;

(Using Moq)

[TestMethod]
public void Jon_Skeet_Is_Saved_If_User_Not_Authenticated()
{
  bool jonWasSaved = false;
  var mockFooService = new Mock<IFooService>();
  mockFooService
       .Expect(x => x.Save(It.Is<Foo>(foo => foo.AnonName == "Jon Skeet")))
       .Callback(() => jonWasSaved = true;);

  FooManager instance = new FooManager(mockFooService.Object);
  Foo testFoo = new Foo();
  testFoo.UserId = 1; // this is not the authenticated id

  instance.baa(foo);

  Assert.IsTrue(jonWasSaved);
}

You may also want to pass in a mock version of whatever service you use to check the AuthetnicatedUser.Id

HTH

Kirschstein
+1  A: 

Maybe you are finding it difficult to test the object because you have more than one activity taking place in a single method.

The overall theme here is controller logic.

  1. Decorate the domain object with user information
  2. Persist the update logic
  3. Determine the next view to render based on success/failure

If you extract another object (IUserDecoratorService) then your code looks like

userService.UpdateUserInformation(foo);

try
{
    _fooService.Save(foo);
}
catch
{
    // Some view, with error stuff now added to 
    return View(...); ViewData.ModelState.
}

// all good, redirect to the proper next view.
return RedirectToAction(...);

This method is simple to test as it is 2 simple interactions with the 2 services and a routing decision which you can already test.

Now you just need to write the tests for your new service:

[Test]
public void ShouldDecorateWithUserIdForAuthenticatedUser()
{
    {setup authenticated user}
    :
    service.UpdateUserInformation(foo);

    Assert.AreEqual(expectedId, foo.UserId);
    Assert.IsNull(foo.AnonEmail);
    Assert.IsNull(foo.AnonEName);

}

[Test]
public void ShouldSpoofTheAllKnowingSkeetIfAnonymousUser()
{
    {setup anonymous user}
    :
    service.UpdateUserInformation(foo);

    Assert.AreEqual(UnassignedId, foo.UserId);
    Assert.AreEqual("Jon@World-Domination", foo.AnonEmail);
    Assert.AreEqual("Jon Skeet", foo.AnonName);

}
Stuart Caborn