Mocking (MOQ) passed parameter methods (WebAPI MVC Controller) - c#

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();

Related

Setup a Mocked (Moq) class that only exposes properties

I am trying to mock (using Moq) a class set a return object on a class that only exposes two properties.
In my limited Moq experience I would normally use a Setup() lamda to define the method call and then Returns() to spit back the desired output.
What I am falling down on here is the Setup(). There isn't a "method" to call as the constructor does the work, populates the two properties and then returns.
My class that I want to mock...obviously dummied down:
public class CarResponse
{
public IMetaModel meta { get; set; }
public List<ICarModel> cars { get; set; }
public CarResponse(Common.Models.Car car)
{
this.cars = new List<ICarModel>();
}
}
My feeble attempt at mocking:
private Mock<CarResponse> _carResponse = new Mock<CarResponse>(MockBehavior.Strict);
_carResponse.Setup( ????? ).Returns(new CarResponse() { meta = new MetaModelV2(), cars = foo });
To further clarify...here is the code I am trying to write a unit test for:
public HttpResponseMessage AddPickup()
{
//....code removed for brevity....
//this repository is mocked and returns the object exactly as I want it
var car = carRepository.GetCar(carId);
if (!errorInfo.Any()) //This check is bogus it never gets sets
{
RequestHelper rqh = new RequestHelper();
response = rqh.CreateResponse(Request, HttpStatusCode.OK, new CarResponse(car));
}
My unit test:
[TestMethod]
public void AddValidPickupCorrectResponse()
{
//arrange
//...lots of code here left off for setting up http context etc
//act---
var response = controller.AddPickup();
//assert
}
If I were to use a precanned object as suggested how would I "hook" it to the code under test. For example I write a unit test that uses my pre-canned object instead of a Moq but how do I get that pre-canned object to be used by the SUT?
There are few problems which can get in the way of properly unit testing the above code:
new-ing up the response helper
new-ing up the CarResponseObject
In essence, unless a class in real POCO (i.e. only data with public setters and getters), using "new" is a killer for unit testing. I.e. it is not a unit test (test the unit/method in isolation). It tests the behavior of the CarResponse ctor, as well as the working of RequestHelper.
Consider the following changes:
Inject the RequestHelper (so you can mock the CreateResponse method)
Use and inject some mapping factory of sort, which can create CarResponseObjects from Car.
Consider CarResponse to implement something like IResponse, so your RequestHelper, or factory, can return interfaces.
With all of the above, your test will look like (pseudo code, not complete):
//arrange
//....
var carInDB = new Car();
_repoMock.Setup(...).Returns(car);
var carResponse = Mock.Of<IResponse>();
_mapperMock.Setup(m=>m.CreateResponse(car).Returns(carResponse);
var responseFromHelper = new WhateverResponseIsNeeded(); //(or create a new mock IResponse - note! new mock, different than car response
_helperMock.Setup(_controller.Request, HttpStatusCode.OK, carResponse).Returns(responseFromHelper);
//act
var response = _controller.AddPickup();
//assert
response.Should().Be.SameInstanceAs(responseFromHelper)
You can use SetupGet and SetupSet to mock properties. However, I don't think you can mock concrete classes.
If you are dealing with a value type you might find it easier to not bother mocking and just used a pre-canned object.

Pass multiple mock objects to a method

I have a method CreateAccount to test. I am using Moq for the same.
Under CreateAccount method, there are multiple table insertion methods which belongs to two classes AccountRepository and BillingRepository
I have setup the Moq but don't know how to use multiple moq objects.
Below is some code snippet
Mock<AccountRepository> moq = new Mock<AccountRepository>();
Mock<BillingRepository> moqBill = new Mock<BillingRepository>();
moq.Setup(x => x.AddTable_1(new AddTable_1 { }));
moq.Setup(x => x.AddTable_2(new AddTable_2 { }));
moqBill.Setup(x => x.Table_3());
CreateAccount method takes four parameters and its under ApplicationService class
public class ApplicationService
{
public CreateAccountServiceResponse CreateAccount(AuthenticateApp App, CustomerInfo Customer, ServiceInfo Service, Optional op)
{
// SOME VALIDATION CODE
//.....................
// SOME CODE TO SAVE DATA INTO TABLES
obj_1.AddTable_1(objdata_1);
obj_1.AddTable_2(objdata_2);
obj_2.AddTable_3(objdata_3);
}
}
Please suggest some solution. How can these three methods will be skipped ?
Thanks in advance.
You have to provide some means to inject obj_1 and obj_2, since they seem to represent your instances of AccountRepository and BillingRepository, resp.
Typically, you might want to do this by using constructor injection. Extending the snippet you provided, this might look like this:
public class ApplicationService
{
private readonly AccountRepository _accountRepository;
private readonly BillingRepository _billingRepository;
public ApplicationService(AccountRepository accountRepository, BillingRepository billingRepository)
{
_accountRepository = accountRepository;
_billingRepository = billingRepository;
}
public CreateAccountServiceResponse CreateAccount(AuthenticateApp App, CustomerInfo Customer, ServiceInfo Service, Optional op)
{
// SOME VALIDATION CODE
//.....................
// SOME CODE TO SAVE DATA INTO TABLES
_accountRepository.AddTable_1(objdata_1);
_accountRepository.AddTable_2(objdata_2);
_billingRepository.AddTable_3(objdata_3);
}
}
Now you can inject your mocks into the class under test:
public void CreateAccount_WhenCalledLikeThis_DoesSomeCoolStuff()
{
var accountRepoMock = new Mock<AccountRepository>();
// set it up
var billingRepository = new Mock<BillingRepository>();
// set it up
var appService = new ApplicationService(accountRepoMock.Object, billingRepoMock.Objcet);
// More setup
// Act
var response = appService.CreateAccount(...);
// Assert on response and/or verify mocks
}

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.

Unit Testing method ASP. NET (NUnit)

I have a controller that need to test. It has a method with the function inside.
public ActionResult GetZZ()
{
ApplyResponseHeaders();
var result = new MediaJsonResult();
using (var str = new StreamReader(Request.InputStream))
{
string inputData = str.ReadToEnd();
MyFunction(inputData, result);
}
return Json(result);
}
I just want to test the function MyFunction. This function is private. How can I do this. Test the entire method is not necessary, because the problems in the appointment of its values ​​in Request.InputStream
Don't try to test private methods ever. These methods are not part of public API and cannot be invoked by caller. Your goal is to satisfy requirements for public API. It really doesn't matter if private method works as expected or not. From caller's point of view this method does not exist and does not have any value.
Instead you should test functionality, which is available via public API, GetZZ() method in your case. But you should mock external dependencies in order to test your controller in isolation with any test data you want.
So, here you have two options. First one is mocking HttpRequest which your controller depends on, and providing test data for input stream (you will have to do lot of work):
var httpRequest = new Mock<HttpRequestBase>();
var stream = new MemoryStream(Encoding.Default.GetBytes("Hello world"));
httpRequest.Setup(r => r.InputStream).Returns(stream);
var httpContext = new Mock<HttpContextBase>();
httpContext.Setup(c => c.Request).Returns(httpRequest.Object);
var controller = new HomeController();
var routeData = new RouteData();
controller.ControllerContext = // set mocked context
new ControllerContext(httpContext.Object, routeData, controller);
var result = (JsonResult)controller.GetZZ();
Assert.That(result.Data, Is.EqualTo(42)); // your assertions here
Another option - hiding this environment-related stuff under some abstraction, which can be easily mocked (of course, you should use better names):
public interface IFoo
{
string Bar();
}
This is a implementation, which uses current context request to get input data:
public class Foo : IFoo
{
public string Bar()
{
using (var str = new StreamReader(HttpContext.Current.Request.InputStream))
{
string inputData = str.ReadToEnd();
return inputData;
}
}
}
Make controller depend on this abstraction:
public class HomeController : Controller
{
private readonly IFoo _foo;
public HomeController(IFoo foo) // inject dependency
{
_foo = foo;
}
public ActionResult GetZZ()
{
ApplyResponseHeaders();
var result = new JsonResult();
MyFunction(_foo.Bar(), result); // use dependency
return result;
}
}
Now you can mock it without any problems:
var foo = new Mock<IFoo>();
foo.Setup(f => f.Bar()).Returns("Hello, TDD");
var controller = new HomeController(foo.Object);
var result = (JsonResult)controller.GetZZ();
Assert.That(result.Data, Is.EqualTo(42));
One easy way is to make the method public. If you can't (or don't want to), you could make the method protected instead of private, then subclass your controller in your test assembly and test it through the derived type.
Something like so:
public class TesterController : YourController
{
public new ActionResult MyFunction(string inputData, MediaJsonResult result)
{
return base.MyFunction(inputData, result);
}
}
You can mark the methods as internal instead of private and then add a InternalsVisibleTo("Path.To.Test.Project") in AssemblyInfo.cs of your controllers.
Not 100% sure agree about NEVER EVER test a private method in your code. Like most things, sometimes it makes sense and being pragmatic is often better then being dogmatic.

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