How can mock dependencies to Web API controller unit test? - c#

In my current MVC application, I have architected a series of command objects to handle business actions. These business actions would be wrapped around service endpoints. These endpoints would also be consumed by an MVC frond-end & a windows app. Every business action will call into a DAO action, which in turn, calls into the required data access repositories to successfully perform the business action. I have listed an example action below.
Busines Action
public class CreateProjectAction
{
IInsertProjectDAOAction InsertProjectDAOAction { get; set; }
public void Execute()
{
// Does some business validation & other logic before
// calling the DAO action
InsertProjectDAOAction.Execute();
}
}
DAO Action
public interface IInsertProjectDAOAction
{
void Execute();
}
public class InsertProjectDAOAction
{
IProjectRepository ProjectRepository { get; set; }
public void Execute()
{
ProjectRepository.Insert();
}
}
Project Repository
public interface IProjectRepository
{
void Insert(Project proj);
// other db methods would be listed here
}
public class ProjectRepository
{
public void Insert(Project proj)
{
// Insert into the data store
}
}
Controller
[HttpPost]
public IHttpActionResult Create(NewProjectModel newProjectModel)
{
var cmdArgs = Mapper.Map<CreateProjectCommand.CreateProjectCommandArgs>(newProjectModel);
var action = new CreateProjectCommand(UserId, cmdArgs);
action.Execute();
if(action.IsSuccessful)
return Ok(project)
else
return InternalServerError(action.Exception);
}
Unit Test
public void InsertWith_ExistingProjectName_Returns_ServerError()
{
var arg = new CreateProjectCommandArgs(){ .... };
var cmd = CreateProjectAction(args);
action.Execute();
Assert.That(action.IsSuccessful, Is.False);
Assert.That(action.Exception, Is.TypeOf<UniqueNameExcepton>());
}
I am using Ninject to assist with the dependency injection between layers. I have a bunch of unit tests around the business 'CreateProjectAction' to test out expected behavior of that object. The business actions are wrapped around a series of Web API service endpoints. I would also like to write tests around my MVC controllers so that I can be sure they work as planned.
I like the architecure so far, but having trouble figuring out how to mock the DAO action properties in the business action when writing unit tests for the mvc controller. I'd love to hear suggestions, other viewpoints, etc ...

Your question is still a bit unclear. It seems likely for example that InsertProjectDAOAction implements the interface IInsertProjectDAOAction, even though your sample code doesn't indicate that it does. It's also unclear what CreateProjectCommand in your controller example is, since it isn't one of your example elements above it.
That said, one approach that you can take is to defer the creation of your commands out to a factory and inject the factory into your controller (through Ninject in your code and as a Mock in your unit tests). This allows you setup a mock chain. You mock the factory and have it return a mock of your action that you're interested in, which you can then setup to do whatever you want. At a very basic level, this might look like this:
public interface ICommandFactory {
IInsertProjectDAOAction CreateInsertProjectAction(int userId);
}
public class CommandFactory : ICommandFactory{
public IInsertProjectDAOAction CreateInsertProjectAction(int userId) {
return new InsertProjectDAOAction(/* userId???? */);
}
}
The controller would do something like this to use the factory:
public IHttpActionResult Create(/* ... */) {
var action = _commandFactory.CreateInsertProjectAction(1234);
action.Execute();
// ...
}
With a test looking something like:
[Test]
public void MyTest() {
var factoryMock = new Mock<ICommandFactory>();
var commandMock = new Mock<IInsertProjectDAOAction>();
factoryMock.Setup(x => x.CreateInsertProjectAction(It.IsAny<int>())).Returns(commandMock.Object);
commandMock.Setup(x => x.Execute()).Throws(new InvalidOperationException("Random failure"));
var controller = new MyController(factoryMock.Object);
try {
controller.Create(/* ... */);
Assert.Fail();
}
catch (InvalidOperationException ex) {
Assert.AreEqual("Random failure", ex.Message);
}
}
This is a general approach that you could take. However, as I've said, that might not be right for your situation, because your question is unclear. I've also ignored other issues about how you create / test your controller in general since that doesn't seem to be what your question is about...

Related

Mocking (MOQ) passed parameter methods (WebAPI MVC Controller)

My apologies in advanced for not knowing the technical name of this scenario. I am mocking for unit test and that is all fine. However on this section of code I have run into a scenario that exceeds my mocking knowledge. Basically I have MethodA that takes 3 parameters. One of the parameters is passed as another method's output.
When I step through the method passed as a parameter is executed
My difficulty is that the passed method is being executed BEFORE my mocked object. Now it seems like a simple solution...mock the second method as well...that is where my knowledge falls down. I don't know how to get the "second" method mock into the testing context.
My controller being tested (simplified of course):
public class OrderController : ApiController
{
public OrderController(IRepositoryK repositoryk)
{}
public HttpResponseMessage NewOrder()
{
...snip....
string x = repositoryk.MethodA("stuff", "moreStuff", MethodB("junk"));
}
public string MethodB(string data)
{
using (var client = new HttpClient())
{...make call to Google API...}
}
}
My test:
[TestMethod]
public void AddOrder_CorrectResponse()
{
private Mock<IRepositoryK> _repK = new Mock<IRepositoryK>();
_repK.Setup(x => x.MethodA(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns("Yippe");
//of course I've left out all the controller buildup and execution stuff.
}
So I really have no desire to dive into MethodB but it seems to be doing it anyway. What am I doing wrong?
TIA
Thank you for your responses. I understand completely what you are saying. I'm trying to get some testing coverage in place before refactoring. So is there no way of keeping methodB from executing and just let my repositoryK mock just return what I've specified in the setup.
Your code is not easy to test, because it has hard dependency on HttpClient. You have nicely separated repository implementation, but if you want to easily test the code you should also separate code which calls Google API. The idea is to have something like this:
// Add interfece for accessing Google API
public interface IGoogleClient
{
string GetData(string data);
}
// Then implementation is identical to MethodB implementation:
public class GoogleClient : IGoogleClient
{
public string GetData(string data)
{
using (var client = new HttpClient())
{
//...make call to Google API...
}
}
}
// Your controller should look like this:
public class OrderController : ApiController
{
private readonly IRepositoryK repositoryk;
private readonly IGoogleClient googleClient;
public OrderController(IRepositoryK repositoryk, IGoogleClient googleClient)
{
this.googleClient = googleClient;
this.repositoryk = repositoryk;
}
public HttpResponseMessage NewOrder()
{
//...snip....
string x = repositoryk.MethodA("stuff", "moreStuff", MethodB("junk"));
}
public string MethodB(string data)
{
return googleClient.GetData(data);
}
}
If you have such setup you can easily mock both IRepositoryK and IGoogleClient:
Mock<IRepositoryK> repK = new Mock<IRepositoryK>();
Mock<IGoogleClient> googleClient = new Mock<IGoogleClient>();
repK.Setup(x => x.MethodA(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Returns("Yippe");
googleClient.Setup(It.IsAny<string>()).Returns("something");
var controller = new OrderController(repK.Object, googleClient.Object);
// Test what you want on controller object
However, if you want to keep your code tightly coupled you can mock the call to MethodB with small changes.
First, you need to make method MethodB virtual, so it could be overridden in mock:
public virtual string MethodB(string data)
{
// your code
}
Then in your test instead of instantiating controller, instantiate and use mock of your controller:
var repK = new Mock<IRepositoryK>();
// create mock and pass the same constructor parameters as actual object
var controllerMock = new Mock<OrderController>(repK.Object);
controllerMock.CallBase = true;
// mock MethodB method:
controllerMock.Setup(x => x.MethodB(It.IsAny<string>())).Returns("data");
// call the method on mock object
// instead of calling MethodB you will get a mocked result
var result = controllerMock.Object.NewOrder();

Unit Testing with DbContext mock through Service Layer

I'm a beginner at writing unit tests and I have a test I'm trying to get working. I'll start of by explaining what I'm trying to test.
I'm trying to test a method which saves messages in a Mvc 4 project. The method is called SaveMessage and is shown below.
namespace ChatProj.Service_Layer
{
public class UserService : IUserService
{
public MessageContext messageContext = new MessageContext();
public UserService()
{
_messageRepository = new MessageRepository(messageContext);
}
private IMessageRepository _messageRepository;
-> public void SaveMessage(Message message)
{
messageContext.Messages.Add(message);
_messageRepository.Save();
}
The _messageRepository.Save in the SaveMessage method is implemented in my DAL layer MessageRepository and looks like this:
public void Save()
{
context.SaveChanges();
}
This way of saving will seem a bit overcomplicated, but I structured the project this way because I didn't want the service layer (IUserService & UserService) to handle operations that could & should (i think) be handled by the Data Access Layer (IMessageRepository & MessageRepository).
Now comes the tricky part. I've been trying to understand how I could unit test this. This is my try:
namespace ChatProj.Tests
{
[TestFixture]
class MessageRepositoryTests
{
[SetUp]
public void Setup()
{
}
[Test]
public void SaveMessage_SaveWorking_VerifyUse()
{
//Arrange
var userServiceMock = new Mock<UserService>();
var message = new Message { MessageID = 0, Name = "Erland", MessageString = "Nunit Test", MessageDate = DateTime.Now };
var repositoryMock = new Mock<IMessageRepository>();
var contextMock = new Mock<MessageContext>();
MessageRepository messageRepository = new MessageRepository(contextMock.Object);
UserService userService = new UserService();
//Act
userService.SaveMessage(message);
//Assert
repositoryMock.Verify(m => m.Save());
userServiceMock.Verify(m => m.SaveMessage(message));
}
}
I get this error: Imgur link , and I'm not quite sure how to solve it. I've tried looking at several other SO posts but I fail to make the test work.
So I'm wondering, how do I practically get my Unit Test to work?
You should setup your MessageContext properties to return fake data and don't make real Db call with SaveChanges method.
Right now it still tries to access a real DB.
But you can setup only virtual properties or if it will be an inteface.
So the best solution is to extract an interface from your MessageContext and inject it into repository. Then you can easily mock your IMessageContext interface and force it to return appropriate in-memory data.
Take a look at these two lines:
UserService userService = new UserService();
//Act
userService.SaveMessage(message);
You're creating a userService instance, and then immediately saving your message. Now jump into the SaveMessage code.
public void SaveMessage(Message message)
{
messageContext.Messages.Add(message);
_messageRepository.Save();
}
Ok, now you're adding stuff to messageContext, and then calling _messageRepository.Save(). But where are messageContext and _messageRepository instantiated?
public MessageContext messageContext = new MessageContext();
public UserService()
{
_messageRepository = new MessageRepository(messageContext);
}
You're creating them at instantiation. The mocks that you've created in your test aren't being used. Instead of creating instances of these objects in the constructor, you might consider passing them into the UserService constructor as arguments. Then, you can pass in mocked instances in your test.

Using a DbContext variable from one Controller to Another

Hi I am using MVC 4 and C# to develop an application that has two controllers:
The first one is called Business, it has a method called Create that calls a method called CreatePartner from another Controller named PartnerController.
public class BusinessController : Controller
{
private storeContext db = new storeContext();
public ActionResult Create(Business business)
{
//Some stuff here
PartnerController pt = new PartnerController();
pt.CreatePartner(int partner_id);
//Here is another stuff that uses db DbContext variable
return RedirectToAction("Index");
}
}
This is the second controller Called Partner
public class PartnerController : Controller
{
private storeContext db = new storeContext();
public void CreatePartner(int partner_id)
{
//Some interesting stuff
}
}
Each controllers has its Dispose() method
The Problem is: After I called the CreatePartnet method from Business controller I try to use the db variable again to save other data but it throws me the following exception:
The operation can not be completed because the DbContext has been disposed
-What is the best way to Use methods from one controller to another that has the same DbContext variable name?.
-Something strange happens: My stuff works locally but when I publish my code in the IIS server is when the app throws that exception.
Thanks!
Might I suggest an alternative approach?
Controllers are not very good places for business logic; that is they're not very good places for "doing stuff". It's often demonstrated in MVC tutorials and examples in this manner but it's really only good for getting into MVC quickly - it's not very good practice.
Furthermore Controllers aren't really supposed to have methods to be called - from themselves or called from another Controller. Controllers should really just contain their Actions.
Instead, extract your logic to an external class. A Service is a design pattern in which commonly used business logic is abstracted away. That way things can have a reference to the service and execute the logic without knowing anything about the implementation.
Observe:
IPartnerService
public interface IPartnerService
{
void CreatePartner(int partnerId);
}
DefaultPartnerService
public class DefaultPartnerService : IPartnerService
{
private StoreContext db;
public DefaultPartnerService()
{
db = new StoreContext();
}
public void CreatePartner(int partnerId)
{
// Something interesting
}
}
BusinessController
public class BusinessController : Controller
{
private IPartnerService _partnerService;
public BusinessController()
{
_partnerService = new DefaultPartnerService();
}
public ActionResult Create(Business business)
{
_partnerService.CreatePartner(business.PartnerId);
return RedirectToAction("Index");
}
}
Of course this approach is also greatly simplified for educational purposes. It's not best practice yet, but it might put you on the right track. Eventually you'll discover problems with this approach and you'll gravitate to reading about Repositories, Unit of Work, Dependency Injection and so on.

How to perform Unit Testing on Create method in MVC?

How to perform a Unit testing on MVC application?
I have created the Controller Location.
It has properties like LocationName,Area,City,PinCode.
Now, I want to perform unit test to check whether Location saves in DB or not.
How to check it.
I have go through tons of videos, every where they just put the Unit test of
Mathematical operations like adding,Dividing , subtracting....
I would like to know how to perform the Unit testing of Create method of MVC
I have code something like below
[HttpPost]
public ActionResult Create(Location location)
{
if (ModelState.IsValid)
{
db.Locations.Add(location);
db.SaveChanges();
return RedirectToAction("Index");
}
}
In order to make your code testable, you should abstract dependencies of controller. It's very handy to use Repository pattern to abstract data access. Inject your repository into controller:
public class LocationController : Controller
{
private ILocationRepository _locationRepository;
public LocationController(ILocationRepository locationRepository)
{
_locationRepository = locationRepository;
}
}
Now you can mock your repository. Here is sample test with Moq framework and MvcContrib:
// Arrange
Mock<ILocationRepository> repository = new Mock<ILocationRepository>();
var controller = new LocationController(repository.Object);
Location location = new Location("New York);
// Act
var result = controller.Create(location);
// Assert
result.AssertActionRedirect()
.ToAction<LocationController>(c => c.Index());
repository.Verify(r => r.Add(location));
repository.Verify(r => r.Save());
And you can implement code, which will pass this test:
[HttpPost]
public ActionResult Create(Location location)
{
if (ModelState.IsValid)
{
_locationRepository.Add(location);
_locationRepository.Save();
return RedirectToAction("Index");
}
}
You can read more on implementing repositories and testing MVC applications here:
Implementing the Repository and Unit of Work Patterns in an ASP.NET MVC Application. Nice feature also to have Unit of Work per request.

unit testing dotnetopenauth ctp

I'm implementing an oauth provider using DotNetOpenAuth CTP library. So I have created an mvc3 application, which has an OAuth Controller with 3 methods in it with the purpose of authorizing third party applications. The controller has an IOAuthService which encapsulates all the logic that the library must do to complete certain tasks, however, the service methods return DotNetOpenOAuth objects that have their constructors protected.
I would like to test the behavior of the methods within my OAuthController, for this, I'm trying to mock my service methods but I havent't been able to do this. I have to tell moq library what type of object I'm expecting the service method to return, and since I cannot access constructors of these objects, I'm not able to perform a test over my controller method.
The controller:
public class OAuthController : Controller
{
private readonly IOAuthService _oAuthService;
public OAuthController(IOAuthService oAuthService)
{
_oAuthService = oAuthService;
}
[Authorize, AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
public ActionResult Authorize()
{
ClientApplication requestingClient;
var request = _oAuthService.ReadAuthorizationRequest();
if (request == null)
{
throw new HttpException((int)HttpStatusCode.BadRequest, "Missing authorization request.");
}
var response = _oAuthService.RequestClientAuthorization(GetIdentity().Name, out requestingClient, request);
if (response != null)
{
return response.AsActionResult();
}
var model = new AuthorizeClientApplicationViewModel
{
ClientApplication = requestingClient.Name,
Scope = request.Scope,
AuthorizationRequest = request,
};
return View(model);
}
public virtual IIdentity GetIdentity()
{
return User.Identity;
}
}
I want to test that whenever a third party app has no authorization, a view will pop up to the user asking for his permission to authorize the app. Fot this i need to mock:
_oAuthService.RequestClientAuthorization
The setup of my test method will then look like :
var oAuthService = new Mock<IOAuthService>();
oAuthService.Setup(a => a.RequestClientAuthorization(userName, out client, pendingRequest)).Returns(new OutgoingWebResponse()); // DotNetOpenAuth doesn't allow me to do the **new OutgoingWebResponse**
PD: For this question I only wrote one of the controller methods, but there are 3, and they have similar scenarios.
One possibility is to write a wrapper (the same way ASP.NET MVC abstracts all the HTTP Context specific stuff):
public abstract class OutgoingWebResponseWrapperBase
{
protected OutgoingWebResponseWrapperBase() { }
public abstract ActionResult AsActionResult();
}
and then have a naïve implementation:
public class OutgoingWebResponseWrapper: OutgoingWebResponseWrapperBase
{
private readonly OutgoingWebResponse _response;
public OutgoingWebResponseWrapper(OutgoingWebResponse response)
{
_response = response;
}
public override ActionResult AsActionResult()
{
return _response.AsActionResult();
}
}
Now modify the IOAuthService.RequestClientAuthorization method to return a OutgoingWebResponseWrapperBase instead of OutgoingWebResponse.
Just like that:
public interface IOAuthService
{
...
OutgoingWebResponseWrapperBase RequestClientAuthorization(...);
}
Obviously your controller code will stay absolutely the same. It's just that now you can mock the return type of the RequestClientAuthorization in your unit test because it is an abstract class. You can also mock the AsActionResult abstract method call to return some expected mocked instance and you will assert in your unit test that the controller action that you are testing returned this expected action result.
If the constructor is protected, then a derived type could access it. Can you simply use Moq to create a mock of OutgoingWebResponse (which internally will make Moq derive from it and call the protected constructor I think) and return that from your mock method implementation?
Something like this:
System.Net.HttpWebResponse mockResponse; // get this from somewhere
new Moq.Mock<DotNetOpenAuth.Messaging.OutgoingWebResponse>(mockResponse, 5);
This should let you mock up an OutgoingWebResponse. The next problem becomes, where do you get yoru HttpWebResponse instance, since that too has only a protected constructor. You could continue the chain and mock up that the same what as OutgoingWebResponse, and see how far you get.

Categories

Resources