ControllerContext.IsChildAction invocation failed with mock behavior Strict. All invocations must have a setup - asp.net-mvc-2

I am toying around to learn how to unit test ASP.NET MVC controller actions. Specifically I'm trying to mock the ControllerContext so that I can test an action that accesses HttpContext.Current.User.Identity.Name.
I'm using Moq.
Things were going pretty well until I turned on MockBehavior.Strict. I knew that this would throw an exception if the code failed to call the thing that I marked Verifiable. Apparently, it will also throw an exception if "extra" methods where I don't provide a setup (like IsChildAction) don't get called.
[TestMethod]
public void Index_Get_AccessesUserIdentityName()
{
// Arrange
var mock = new Mock<ControllerContext>(MockBehavior.Strict);
mock.SetupGet(p => p.HttpContext.User.Identity.Name).Returns("treycarroll").Verifiable();
HomeController controller = new HomeController();
controller.ControllerContext = mock.Object;
// Act
ViewResult result = controller.Index() as ViewResult;
// Assert
mock.Verify();
...
}
Here is the Controller action that I'm testing:
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!"+User.Identity.Name;
return View();
}
The exception is triggered when the return View(); statement is executed. The error message tells me that I need a setup method for the call to IsChildAction so I updated my test class to this:
[TestMethod]
public void Index_Get_AccessesUserIdentityName()
{
// Arrange
var mock = new Mock<ControllerContext>(MockBehavior.Strict);
string expectedUserName = "treycarroll";
mock.SetupGet(p => p.HttpContext.User.Identity.Name).Returns(expectedUserName).Verifiable();
mock.SetupGet(m => m.IsChildAction).Returns(true).Verifiable();
HomeController controller = new HomeController();
controller.ControllerContext = mock.Object;
// Act
ViewResult result = controller.Index() as ViewResult;
string actualUserName = controller.ControllerContext.HttpContext.User.Identity.Name;
// Assert
mock.Verify();
Assert.AreEqual(actualUserName, expectedUserName);
Assert.IsNotNull(result);
}
...
After which I get a similar error about no setup method for ControllerContext.RouteData. By process of elimination I could wind up adding Setup methods for all the missing calls, but this doesn't seem right. Maybe I'm misunderstanding the use of MockBehavior.Strict, but I thought that you turn this on in order to avoid getting default values for your properties (such as null for the User object that I want to inspect). What am I missing here?

A strict mock will fail immediately if anything differs from the expectations. So this means, that if any method call not specified in expectation will fail. On the other hand, a non-strict mock ignore, such calls

Related

How to Unittest a Factory with dependencies

How can I test my factory with the entity manager? I have an error because I need to make my container return an instance of a class created from doctrine ( I do not even know what there is returned).
How can I create a test that I can make pass?
// factory i want to test
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$googleAppOption = $container->get(GoogleAppOptions::class);
$em = $container->get('doctrine.entity_manager.orm_default');
return new GoogleTokenHandler($googleAppOption, new GoogleTokenClient(), $em);
}
//test function
public function testReturnsTokenHandlerInstance()
{
$googleOptionsFactory = new GoogleOptionsFactory();
$googleOptions = $googleOptionsFactory($this->container->reveal(), null);
$this->container->get(GoogleAppOptions::class)->willReturn($googleOptions);
$googleTokenHandlerFactory = new GoogleTokenHandlerFactory($this->container);
$tokenHandler = $googleTokenHandlerFactory($this->container->reveal(), null);
$this->assertInstanceof(GoogleTokenHandler::class, $tokenHandler);
}
Th fact that this is hard to test is a good sign that there is something smelly about this. In your case it's quite obviously the container being injected and then being used to locate services to work upon. I would recommend rewriting this class to inject both the OptionsFactory (or even better just the options) and the EntityManager as well as the dynamically created GoogleClient in the constructor. What you would arrive at is an invoke that pretty much looks like this:
return new GoogleTokenHandler(
$this->optionsFactory,
$this->tokenClient,
$this->entityManager
);
As you can see you neither use the $requestedName nor the optional $options being passed to your __invoke. That's a bit odd, but that won't bother us with the tests. Now you can simply mock out the services in your test and check whether invoke returns the correct instance:
public function testFactoryInvokeReturnsInstance()
{
$optionsFactory = $this->prophesize(OptionsFactory::class);
$tokenClient = $this->prophesize(GoogleTokenClient::class);
$entityManager = $this->prophesize(EntityManager::class);
$factory = new MyFactory(
$optionsFactory->reveal(),
$tokenClient->reveal(),
$entityManager->reveal()
);
$this->assertInstanceOf(GoogleTokenHandler::class, $factory->__invoke());
// Alternatively you can use the __invoke-magic directly:
$this->assertInstanceOf(GoogleTokenHandler::class, $factory());
}
You could do the same with your class but basically you would have to add a Container and then stub out the get-method for all of the services being fetched from it. For example you are missing the entity manager in your snippet. Should the GoogleTokenClient being created in your method require some arguments/options there is no way to mock that behavior and in fact you won't be able to switch it out without changing the code. Whereas by injecting it in the constructor you can just re-configure your container to pass in a different object.
For posterity, your complete factory would probably look something like this:
class Factory {
private $optionsFactory;
private $tokenClient;
private $entityManager;
public function __construct(GoogleTokenClient $tokenClient, ...)
{
$this->tokenClient = $tokenClient;
...
}
public function __invoke() { return new GoogleTokenHandler(...); }
}

Unit Testing MVVMLight Messenger

Is it possible to write a Unit Test that calls the Messenger.Default.Register method and then write an Assertion to be used by the Action?
I would like to determine if my ViewModel is sending the correct message after calling an Execute on one of my Commands.
I have tried writing the Assert.AreEqual as the Action however this doesn't seem to be working correctly.
Sounds like a job for mocking! Assuming you're passing in the messenger interface to your viewmodel (because dependency inversion is a Good Thing, for this very reason), your code should look something like this if I understand you correctly:
public class YourViewModel
{
readonly IMessenger messenger;
public YourViewModel(IMessenger messenger)
{
this.messenger = messenger;
// setup of your delegate command to call Execute
}
void Execute(object parameter)
{
messenger.Send(new YourMessageType());
}
}
Then in your unit test you'd mock the messenger and verify that the right method is called, which in this case is Send. So, using the popular mocking framework Moq:
public class YourViewModelTests
{
[Test]
public void Execute_Always_SendsYourMessageType()
{
// arrange
var mockRepository = new MockRepository(MockBehavior.Loose);
var mockMessenger = mockRepository.Create<IMessenger>();
var systemUnderTest = new YourViewModel(mockMessenger.Object);
// act
systemUnderTest.YourCommand.Execute(null);
// assert
mockMessenger.Verify(p => p.Send<YourMessageType>(
It.Is(m => /* return true if it's the right message */)));
}
}
Usually I'd move the just about all of the "arrange" phase into a test setup method, but you should get the idea.
If you'd still like to do it without mocking the messenger and also use Messenger.Default, you can do the following:
public class YourViewModelTests
{
[Test]
public void Execute_Always_SendsYourMessageType()
{
// arrange
var systemUnderTest = new YourViewModel();
// Set the action to store the message that was sent
YourMessageType actual;
Messenger.Default.Register<YourMessageType>(this, t => actual = t);
// act
systemUnderTest.YourCommand.Execute(null);
// assert
YourMessageType expected = /* set up your expected message */;
Assert.That(actual, Is.EqualTo(expected));
}
}
Alternatively, for each test it is possible to create a separate copy of the Messenger. For the runtime you want to use the Default instance of the Messenger, but for Unit Tests, as I said, create a separate copy for each test:
return new GalaSoft.MvvmLight.Messaging.Messenger(); // Unit Tests
return GalaSoft.MvvmLight.Messaging.Messenger.Default; // Runtime
Otherwise one might end up re-inventing the wheel, since in more complex situations where there is a need to test ViewModel communications, you will have to manage Messenger subscribers, message types an so on. Then probably writing unit tests for the messenger mock making sure it works in the same way as the original messenger. There is nothing in the engine of the Messenger that should be different when comparing Runtime and Test executions.
So for testing a factory returns the same instance of the Messenger. Test method subscribes and waits, ViewModel publishes; then Test accepts and exits. Otherwise Test times out and reports an error. I found this approach more "closer to reality" than mocking the messenger and verifying through the mock that the method was called.

Decouple EF queries from BL - Extension Methods VS Class-Per-Query

I have read dozens of posts about PROs and CONs of trying to mock \ fake EF in the business logic.
I have not yet decided what to do - but one thing I know is - I have to separate the queries from the business logic.
In this post I saw that Ladislav has answered that there are 2 good ways:
Let them be where they are and use custom extension methods, query views, mapped database views or custom defining queries to define reusable parts.
Expose every single query as method on some separate class. The method
mustn't expose IQueryable and mustn't accept Expression as parameter =
whole query logic must be wrapped in the method. But this will make
your class covering related methods much like repository (the only one
which can be mocked or faked). This implementation is close to
implementation used with stored procedures.
Which method do you think is better any why ?
Are there ANY downsides to put the queries in their own place ? (maybe losing some functionality from EF or something like that)
Do I have to encapsulate even the simplest queries like:
using (MyDbContext entities = new MyDbContext)
{
User user = entities.Users.Find(userId); // ENCAPSULATE THIS ?
// Some BL Code here
}
So I guess your main point is testability of your code, isn't it? In such case you should start by counting responsibilities of the method you want to test and than refactor your code using single responsibility pattern.
Your example code has at least three responsibilities:
Creating an object is a responsibility - context is an object. Moreover it is and object you don't want to use in your unit test so you must move its creation elsewhere.
Executing query is a responsibility. Moreover it is a responsibility you would like to avoid in your unit test.
Doing some business logic is a responsibility
To simplify testing you should refactor your code and divide those responsibilities to separate methods.
public class MyBLClass()
{
public void MyBLMethod(int userId)
{
using (IMyContext entities = GetContext())
{
User user = GetUserFromDb(entities, userId);
// Some BL Code here
}
}
protected virtual IMyContext GetContext()
{
return new MyDbContext();
}
protected virtual User GetUserFromDb(IMyDbContext entities, int userId)
{
return entities.Users.Find(userId);
}
}
Now unit testing business logic should be piece of cake because your unit test can inherit your class and fake context factory method and query execution method and become fully independent on EF.
// NUnit unit test
[TestFixture]
public class MyBLClassTest : MyBLClass
{
private class FakeContext : IMyContext
{
// Create just empty implementation of context interface
}
private User _testUser;
[Test]
public void MyBLMethod_DoSomething()
{
// Test setup
int id = 10;
_testUser = new User
{
Id = id,
// rest is your expected test data - that is what faking is about
// faked method returns simply data your test method expects
};
// Execution of method under test
MyBLMethod(id);
// Test validation
// Assert something you expect to happen on _testUser instance
// inside MyBLMethod
}
protected override IMyContext GetContext()
{
return new FakeContext();
}
protected override User GetUserFromDb(IMyContext context, int userId)
{
return _testUser.Id == userId ? _testUser : null;
}
}
As you add more methods and your application grows you will refactor those query execution methods and context factory method to separate classes to follow single responsibility on classes as well - you will get context factory and either some query provider or in some cases repository (but that repository will never return IQueryable or get Expression as parameter in any of its methods). This will also allow you following DRY principle where your context creation and most commonly used queries will be defined only once on one central place.
So at the end you can have something like this:
public class MyBLClass()
{
private IContextFactory _contextFactory;
private IUserQueryProvider _userProvider;
public MyBLClass(IContextFactory contextFactory, IUserQueryProvider userProvider)
{
_contextFactory = contextFactory;
_userProvider = userProvider;
}
public void MyBLMethod(int userId)
{
using (IMyContext entities = _contextFactory.GetContext())
{
User user = _userProvider.GetSingle(entities, userId);
// Some BL Code here
}
}
}
Where those interfaces will look like:
public interface IContextFactory
{
IMyContext GetContext();
}
public class MyContextFactory : IContextFactory
{
public IMyContext GetContext()
{
// Here belongs any logic necessary to create context
// If you for example want to cache context per HTTP request
// you can implement logic here.
return new MyDbContext();
}
}
and
public interface IUserQueryProvider
{
User GetUser(int userId);
// Any other reusable queries for user entities
// Non of queries returns IQueryable or accepts Expression as parameter
// For example: IEnumerable<User> GetActiveUsers();
}
public class MyUserQueryProvider : IUserQueryProvider
{
public User GetUser(IMyContext context, int userId)
{
return context.Users.Find(userId);
}
// Implementation of other queries
// Only inside query implementations you can use extension methods on IQueryable
}
Your test will now only use fakes for context factory and query provider.
// NUnit + Moq unit test
[TestFixture]
public class MyBLClassTest
{
private class FakeContext : IMyContext
{
// Create just empty implementation of context interface
}
[Test]
public void MyBLMethod_DoSomething()
{
// Test setup
int id = 10;
var user = new User
{
Id = id,
// rest is your expected test data - that is what faking is about
// faked method returns simply data your test method expects
};
var contextFactory = new Mock<IContextFactory>();
contextFactory.Setup(f => f.GetContext()).Returns(new FakeContext());
var queryProvider = new Mock<IUserQueryProvider>();
queryProvider.Setup(f => f.GetUser(It.IsAny<IContextFactory>(), id)).Returns(user);
// Execution of method under test
var myBLClass = new MyBLClass(contextFactory.Object, queryProvider.Object);
myBLClass.MyBLMethod(id);
// Test validation
// Assert something you expect to happen on user instance
// inside MyBLMethod
}
}
It would be little bit different in case of repository which should have reference to context passed to its constructor prior to injecting it to your business class.
Your business class can still define some queries which are never use in any other classes - those queries are most probably part of its logic. You can also use extension methods to define some reusable part of queries but you must always use those extension methods outside of your core business logic which you want to unit test (either in query execution methods or in query provider / repository). That will allow you easy faking query provider or query execution methods.
I saw your previous question and thought about writing a blog post about that topic but the core of my opinion about testing with EF is in this answer.
Edit:
Repository is different topic which doesn't relate to your original question. Specific repository is still valid pattern. We are not against repositories, we are against generic repositories because they don't provide any additional features and don't solve any problem.
The problem is that repository alone doesn't solve anything. There are three patterns which have to be used together to form proper abstraction: Repository, Unit of Work and Specifications. All three are already available in EF: DbSet / ObjectSet as repositories, DbContext / ObjectContext as Unit of works and Linq to Entities as specifications. The main problem with custom implementation of generic repositories mentioned everywhere is that they replace only repository and unit of work with custom implementation but still depend on original specifications => abstraction is incomplete and it is leaking in tests where faked repository behaves in the same way as faked set / context.
The main disadvantage of my query provider is explicit method for any query you will need to execute. In case of repository you will not have such methods you will have just few methods accepting specification (but again those specifications should be defined in DRY principle) which will build query filtering conditions, ordering etc.
public interface IUserRepository
{
User Find(int userId);
IEnumerable<User> FindAll(ISpecification spec);
}
The discussion of this topic is far beyond the scope of this question and it requires you to do some self study.
Btw. mocking and faking has different purpose - you fake a call if you need to get testing data from method in the dependency and you mock the call if you need to assert that method on dependency was called with expected arguments.

Can I use NUnit TestCase to test mocked repository and real repository

I would like to be able to run tests on my fake repository (that uses a list)
and my real repository (that uses a database) to make sure that both my mocked up version works as expected and my actual production repository works as expected. I thought the easiest way would be to use TestCase
private readonly StandardKernel _kernel = new StandardKernel();
private readonly IPersonRepository fakePersonRepository;
private readonly IPersonRepository realPersonRepository;
[Inject]
public PersonRepositoryTests()
{
realPersonRepository = _kernel.Get<IPersonRepository>();
_kernel = new StandardKernel(new TestModule());
fakePersonRepository = _kernel.Get<IPersonRepository>();
}
[TestCase(fakePersonRepository)]
[TestCase(realPersonRepository)]
public void CheckRepositoryIsEmptyOnStart(IPersonRepository personRepository)
{
if (personRepository == null)
{
throw new NullReferenceException("Person Repostory never Injected : is Null");
}
var records = personRepository.GetAllPeople();
Assert.AreEqual(0, records.Count());
}
but it asks for a constant expression.
Attributes are a compile-time decoration for an attribute, so anything that you put in a TestCase attribute has to be a constant that the compiler can resolve.
You can try something like this (untested):
[TestCase(typeof(FakePersonRespository))]
[TestCase(typeof(PersonRespository))]
public void CheckRepositoryIsEmptyOnStart(Type personRepoType)
{
// do some reflection based Activator.CreateInstance() stuff here
// to instantiate the incoming type
}
However, this gets a bit ugly because I imagine that your two different implementation might have different constructor arguments. Plus, you really don't want all that dynamic type instantiation code cluttering the test.
A possible solution might be something like this:
[TestCase("FakePersonRepository")]
[TestCase("TestPersonRepository")]
public void CheckRepositoryIsEmptyOnStart(string repoType)
{
// Write a helper class that accepts a string and returns a properly
// instantiated repo instance.
var repo = PersonRepoTestFactory.Create(repoType);
// your test here
}
Bottom line is, the test case attribute has to take a constant expression. But you can achieve the desired result by shoving the instantiation code into a factory.
You might look at the TestCaseSource attribute, though that may fail with the same error. Otherwise, you may have to settle for two separate tests, which both call a third method to handle all of the common test logic.

UrlHelper's RouteUrl returning Empty String in Tests

I am having an issue where UrlHelper's RouteUrl method only returns an empty string when run in my tests, though function properly when executing in the real HttpContext. It is, however, finding the route - as I do properly get an exception if I try to resolve a route name which has not been defined.
I have mocked the HttpContext and friends using the code provided by Scott Hanselman/Kzu and added the code needed to bootstrap the Application's Routes into the mocked instance
To reduce the number of variables in my situation, I've written a simple test:
[Test]
public void UrlHelperReturnsCorrectUrl()
{
var controller = new MyController();
controller.SetFakeControllerContext().LoadUrlHelper();
Assert.AreEqual("My/Route/Path", controller.Url.RouteUrl("MyRoute"));
}
Interestingly enough, accessing the RouteCollection directly and using VirtualPath does work:
[Test]
public void GetVirtualPathReturnsCorrectUrl()
{
var controller = new AccountController();
controller.SetFakeControllerContext().LoadUrlHelper();
Assert.AreEqual("My/Route/Path",
Controller.Url.RouteCollection["MyRoute"]
.GetVirtualPath(
controller.Url.RequestContext,
new RouteValueDictionary())
.VirtualPath);
}
For reference, Here is my implementation of the LoadUrlHelper extension method:
public static Controller LoadUrlHelper(this Controller controller)
{
var routes = new RouteCollection();
MvcApplication.RegisterRoutes(routes);
controller.Url = new UrlHelper(
controller.ControllerContext.RequestContext,
routes);
return controller;
}
And here is my route as defined in my application's Global.asax:
routes.MapRoute(
"MyRoute", "My/Route/Path",
new {controller = "Home", action = "Index"});
Has anyone run into this? Am I missing something?
EDIT:
I've followed the MVC code down to the point that it hands the route processing off to System.Routing and found something very interesting. The code that MVC eventually runs to lookup the desired URL (condensed, of course) returns an empty string:
Controller.Url.RouteCollection.GetVirtualPath(
Controller.Url.RequestContext,
"MyRoute", new RouteValueDictionary()).VirtualPath;
whereas an extremely similar variant returns the expected string:
Controller.Url.RouteCollection["MyRoute"].GetVirtualPath(
Controller.Url.RequestContext,
new RouteValueDictionary()).VirtualPath;
I can't seem to go any further in the underlying code to see what is actually happening differently here, but thought it might help someone understand what setup I am missing. (I'm not going to yell bug yet, as the fact stands that the UrlHelpers do work when in a real HttpContext)
The solution to my problem was already posted to another SO question.
I had tried to incorporate this solution piece-meal earlier but did so poorly. Once I copied it entirely and modified for my situation, it worked perfectly.
Here is a more generic version that can be reused across many tests (if placed in a base test fixture class or something similar).
Usage:
var controller = GetController<MyController>();
controller.MyAction();
//...
Method:
protected T GetController<T>() where T : Controller, new()
{
var routes = new RouteCollection();
MvcApplication.RegisterRoutes(routes);
var request = new Mock<HttpRequestBase>(MockBehavior.Strict);
request.SetupGet(x => x.ApplicationPath).Returns("/");
request.SetupGet(x => x.Url).Returns(new Uri("http://localhost", UriKind.Absolute));
request.SetupGet(x => x.ServerVariables).Returns(new System.Collections.Specialized.NameValueCollection());
var response = new Mock<HttpResponseBase>(MockBehavior.Strict);
response.Setup(x => x.ApplyAppPathModifier(It.IsAny<string>())).Returns((string p) => p);
var context = new Mock<HttpContextBase>(MockBehavior.Strict);
context.SetupGet(x => x.Request).Returns(request.Object);
context.SetupGet(x => x.Response).Returns(response.Object);
var controller = new T();
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);
controller.Url = new UrlHelper(new RequestContext(context.Object, new RouteData()), routes);
return controller;
}