Seems like Moq is caching data I set up as return. When I do this:
var service = new Mock<AlbumService>();
service.Setup(x => x.CreateOne()).Returns(new AlbumService().CreateOne());
it returns the same object even thought AlbumService.CreateOne() returns new Album instance.
Is it possible to make Moq call the Returns Action every time I access CreateOne() ?
This ought to help:
var service = new Mock<AlbumService>();
service.Setup(x => x.CreateOne()).Returns(() => new AlbumService().CreateOne());
To elaborate, the Returns method accepts an object of the return type or a delegate that will evaluate to the return type. The delegate is invoked whenever the mocked method is invoked.
Related
I am testing a method which will call another method if certain parameters are certain values and not if they are other.
I was using Moq's Verify to test this. However when I use the xUnit to see if the method is not called when sending parameters with data which should not make the method call the 2nd method.
Problem is that I cannot do
mockObject.Verify();
Assert.Throws<Moq.MockVerificationException>(()=>mockObject.Method());
I changed from MSTest to xUnit because the support for throws was built in and I had to have the ExpectedException attribute decorating my test method before.
I tried to cast the Moq non-public exception to the public parent Moq.MoqException but that will throw an error.
so I think I may have to do:
try {moqObj.Verify();}
catch(Moq.Exception mve)
{
Assert.SomethingIsException();
}
As I understand, you're just trying to verify whether certain methods are called or not? If so, try this:
var theThing = new Mock<IThing> ();
theThing.Verify (x => x.DoSomething ("a"), Times.Never);
theThing.Verify (x => x.DoSomething ("b"), Times.Once);
If you need to invoke another method after the first method is called, you could use a callback:
theThing.Setup (x => x.DoSomething ("a")).Callback (() => {});
I am using moq for unit testing an ASP.NET Http Handler.
Here I am trying to access the HttpRequest instance for the current request by using the Request property of the HttpRequestBase class.
As we know simplified syntax can be used for accessing data from the QueryString, Form, Cookies, or ServerVariables collections i.e. Request["key"]. (Which is being used in the ProcessRequest method of handler)
But I am not able to get the querystring value. Code is as follows:
Test class
[TestMethod()]
private static void MockProcessRequestExecution(AbcHandler abcHandler)
{
NameValueCollection queryString = new NameValueCollection();
queryString.Add("employeeid", "22");
Mock<HttpContextBase> testHttpContext = new Mock<HttpContextBase>();
Mock<HttpResponseBase> testHttpResponse = new Mock<HttpResponseBase>();
Mock<HttpRequestBase> testHttpRequest = new Mock<HttpRequestBase>();
testHttpContext.SetupGet(context => context.Response).Returns(testHttpResponse.Object);
testHttpContext.SetupGet(context => context.Request).Returns(testHttpRequest.Object);
testHttpRequest.SetupGet(request => request.QueryString).Returns(queryString);
testHttpContext.SetupGet(context => context.Request.QueryString).Returns(queryString);
testHttpResponse.SetupSet(response => response.ContentType = "text/plain");
abcHandler.ProcessRequest(testHttpContext.Object);
testHttpResponse.VerifyAll();
}
Inside the handler method code is extracting request variable as following:
ProcessRequest(HttpContextBase context)
{
var employee = context.Request["employeeid"];
}
The value of employeeid is coming as null.
I am getting the value if it written as context.Request.QueryString["employeeid"], but the code written in the ProcessRequest method can not be changed.
So the question is, how to get the value of Request key: "employeeid"
Your code uses the Request Item property which does not only look at the query string. From msdn:
Gets the specified object from the QueryString, Form, Cookies, or ServerVariables collections.
As you are mocking the Request object, you will need to mock the Item property as well, which is what your code uses. (The code in the real HttpRequest class that looks at the QueryString property is not executed, since you are using a mock and not the real object!)
Unfortunately, you need to manually setup the Item property in the mock for every key, as in:
testHttpRequest.SetupGet(r => r["employeeid"]).Returns("22");
You could still create a NameValueCollection in your unit test and use a loop to setup the Item property for each key in the query string. This would also allow you to test code that uses both Request["employeeid"] and Request.QueryString["employeeid"] (which would return the same values).
NameValueCollection queryString = new NameValueCollection{ {"employeeid", "22"} };
//Setup Request Item property for each key in the query string
foreach (var qsKey in queryString.AllKeys)
{
var key = qsKey;
testHttpRequest.SetupGet(r => r[key]).Returns(queryString[key]);
}
//You can still mock the Request.QueryString using the same values
testHttpRequest.SetupGet(r => r.QueryString).Returns(queryString);
I'm trying to put together my first CRUD app using AngularJS and Asp.Net Web Api. I have setup the controller with a newMember object:
$scope.newMember = {};
And then call the insert in the factory method as:
dataService.insertMember($scope.newMember);
This calls the method in the dataService:
var _insertMember = function(member) {
return $http.post("/api/clubmembers/", member);
};
which fires the Web Api Post method
public HttpResponseMessage Post([FromBody]PersonViewModel member)
{
//if (_repo.AddClubMember(member) && _repo.Save())
if (_repo.AddClubMember(member) && _repo.Save())
{
return Request.CreateResponse(HttpStatusCode.Created, member);
}
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
I have checked the data in the Angular part of the app and the correct data is passed via $scope.newMember, but when it reaches the Web Api Post method the member parameter is always Null.
If I modify the controller method to the following it passes the data to the Post method as expected:
var testData2 = {
FirstName: $scope.newMember.FirstName,
LastName: $scope.newMember.LastName
};
var a = 1;
dataService.insertMember(testData2);
Is it possible to pass $scope.newMember as the parameter or do I have to fill in the details as of the amended code?
Thanks
Mark
Check your code carefully, I would say (based on your experience described in the question) there will be some typo.
Call with explicit {} - empty object
If you will call your service like this:
dataService.insertMember({}); // just created empty object
you will get instantiated object on your API Post method PersonViewModel member
Call with explicit null or undefined
but in case, that you will call one of these
dataService.insertMember(null);
dataService.insertMember(undefined);
the API Post method will be provided with NULL.
typo (incorrect property name), i.e. undefined
And what that means? that you most likely, somewhere in the call chain used something like this
$scope.newMember ...
...
dataService.insertMember($scope.newMemberXXX);
where newMemberXXX represents any undefined property, resulting in undefined to be passed
If you add FirstName and LastName properties to newMember it should work fine:
$scope.newMember = {};
$scope.newMember.FirstName = "First Name";
$scope.newMember.LastName = "Last Name";
dataService.insertMember($scope.newMember);
Thing is, $scope.newMember has to match the properties and structure of PersonViewModel for the Web Api to be able to match the two types.
Let us know if this works.
I am setting up a Mock as shown below. It is passed into the constructor of the target. The target has a Decrypt method that is called twice within the lifetime of the target. Each time the Decrypt method is called, it Disposes of the certificate that is "newed" up in the Setup. However, when calling the Decrypt object the second time, I am getting an ObjectDisposed method upon attempting the decryption. If I replace this Mock with a Fake implementation of ICertificateHelperAdapter that calls GetCertificate(), then the second call to Decrypt works properly.
I am deducing that when I use the Mock, it is not returning me a new instance of the object on subsequent calls to GetCertificate. Is this by design?
private Mock<ICertificateHelperAdapter> GetCertificateHelperAdapter()
{
Mock<ICertificateHelperAdapter> certificateHelper = new Mock<ICertificateHelperAdapter>();
certificateHelper.Setup(
ch => ch.GetCertificate(CertStoreName.My, StoreLocation.LocalMachine, It.IsAny<string>())).Returns(this.GetCertificate()).Verifiable();
return certificateHelper;
}
private X509Certificate2 GetCertificate()
{
return new X509Certificate2(Environment.CurrentDirectory + "\\" + "azureconfig.pfx", "dingos");
}
The different overloads of Returns<T> behaves differently:
The one with T Returns<T>(T value) what you are using is always returning the same instance.
But there is a lazy version which uses Func<T>. They are looks like T Returns<T>(Func<T> value) and they will evaluate each time the parameter function when the setup method is called.
Sample from the Moq site:
// lazy evaluating return value
mock.Setup(foo => foo.GetCount()).Returns(() => count);
Change your setup to:
certificateHelper.Setup(ch =>
ch.GetCertificate(CertStoreName.My, StoreLocation.LocalMachine, It.IsAny<string>()))
.Returns(() => this.GetCertificate()).Verifiable(); //note the lambda in Returns
And it will call your GetCertificate() twice.
Since I'm having problem with unit testing RenderPartialViewToString() with Moq framework (ASP.NET MVC - Unit testing RenderPartialViewToString() with Moq framework?), I'm thinking about getting my controller directly, without using Moq for these particular test, however, how do I mocks (or set) the HttpContext for my test without using any Moq framework?
I need to able to do something similar to this, without Moq of course:
var mockHttpContext = new Mock<ControllerContext>();
mockHttpContext.SetupGet(p => p.HttpContext.User.Identity.Name).Returns("n1\\test");
mockHttpContext.SetupGet(p => p.HttpContext.Request.IsAuthenticated).Returns(true);
Thank you very much.
If your controller need authentication info from HttpContext, I would:
Create a new class that wraps the calls you care about. Looks like you want Name and IsAuthenticated. The new class can be AuthenticationService or something.
In the methods/properties in AuthenticationService, call into the real HttpContext, like HttpContext.Current.user.Identity.Name.
Create an interface over the new
AuthenticationService with the
public methods/properties you care about.
Inject the IAuthenticationService
into your controller under test in
the constructor. Looks like you may already be doing that with other dependencies in the controller.
Now you can mock
IAuthenticationService and it's
return values without needing to
call into the real HttpContext.
Here are more details from a blog post I did http://www.volaresystems.com/Blog/post/2010/08/19/Dont-mock-HttpContext.aspx. I'm using RhinoMocks instead of Moq, but the concept is the same for staying away from HttpContext.
You can mock it as follows and declare a stringBuilder object that accepts the output.
var response = new Mock<HttpResponseBase>();
response.Setup(x => x.Write(It.IsAny<string>())).Callback<string>(y => _stringBuilder.Append(y));
var url = new Uri("http://localhost/Home/");
var request = new Mock<HttpRequestBase>();
request.Setup(x => x.Url).Returns(url);
request.Setup(x => x.ApplicationPath).Returns("");
var httpContext = new Mock<HttpContextBase>();
httpContext.Setup(x => x.Request).Returns(request.Object);
httpContext.Setup(x => x.Response).Returns(response.Object);
_controllerContext = new Mock<ControllerContext>();
_controllerContext.Setup(x => x.HttpContext).Returns(httpContext.Object);
_homeController = autoMock.Create<HomeController>();
_homeController.ControllerContext = _controllerContext.Object;
You execute your action as follows:
var action=_homeController.Action(<parameters>);
action.ExecuteResult();
and now your stringbuilder object i.e _stringBuilder will have the result output whatever type it is and you can test it.