I'm trying to unit test my routes, and I'm starting to hit a problem. Some of the action method parameters won't be coming from the URL anymore, but instead will be supplied by an action filter, based on this article: http://haacked.com/archive/2010/02/21/manipulating-action-method-parameters.aspx
The problem is that I have a url: /some/path/id which maps to an action method public ViewResult Action(int id, Guid sessionId) where sessionId is being added to the action parmaters by the action filter. There's now now way that I can see to make this test pass without making Guid a Guid?:
"~/some/path/1".ShouldMapTo<SomeController>(x => x.Action(1, <anyGuid>));
Any ideas?
There's now no way that I can see to make this test pass without making Guid a Guid?
Well actually there is a way.
If you are using Rhino Mocks (which is bundled by default with MvcContrib.TestHelper, so you are already implicitly using it):
"~/home/action/1"
.ShouldMapTo<SomeController>(x => x.Action(1, Arg<Guid>.Matches(y => true)));
and if you are using Moq:
"~/some/action/1"
.ShouldMapTo<SomeController>(x => x.Action(1, It.IsAny<Guid>()));
and if you are using some other mocking framework check the documentation about the syntax that would allow you to specify a parameter constraint that could be anything.
Related
Im testing a Soap web service with getMockFromWsdl from phpunit, for unit testing within laravel works fine, but when I try to replace the SoapClient in a feature test, it always fails, like the web service never called, but actually the mock is called.
I suspect that laravel is cloning somewhere my $this->soapClient because if I debug the code, it calls the soap mock and gets what is faked in the mock but always receive the error:
Expectation failed for method name is equal to <string:GetToken> when invoked at least once.
Expected invocation at least once but it never occurred.
My code is like:
public function test_soap_call()
{
$this->soapClient = $this->getMockFromWsdl(dirname(__FILE__).'/../Mocks/service.wsdl');
$this->soapClient->expects($this->atLeastOnce())
->method('GetToken')
->with(['Code' => '03600', 'User' => 'username'])
->willReturn(unserialize('O:8:"stdClass":1:{s:26:"GetTokenResult";s:36:"5aae60ec-2bcd-459d-a135-a20eb7c10007";}'));
$this->app->instance('MySoapClient', $this->soapClient);
$this->postJson('/api/order', $this->getValidRequest());
}
and in my controller (/api/order) I have
$soap = $this->app->make('MySoapClient');
$soap->GetToken(['Code' => '03600', 'User' => 'username']);
Am I using correctly the Laravel Service Container?
PD: Something similar happened to me, when doing a Spy and using $app->instance, where I was trying to get what was passed to an object, but always got null. I solved it declaring the field of the spy static.
Check this from php.net:
http://php.net/manual/en/language.oop5.references.php
... "objects are passed by references by default". This is not completely true. ...
I made a custom report in AX2012, to replace the WHS Shipping pick list. The custom report is RDP based. I have no trouble running it directly (with the parameters dialog), but when I try to use the controller (WHSPickListShippingController), I get an error saying "Pre-Processed RecId not found. Cannot process report. Indicates a development error."
The error is because in the class SrsReportProviderQueryBuilder (setArgs method), the map variable reportProviderParameters is empty. I have no idea why that is. The code in my Data provider runs okay. Here is my code for running the report :
WHSWorkId id = 'LAM-000052';
WHSPickListShippingController controller;
Args args;
WHSShipmentTable whsShipmentTable;
WHSWorkTable whsWorkTable;
clWHSPickListShippingContract contract; //My custom RDP Contract
whsShipmentTable = WHSShipmentTable::find(whsWorkTable.ShipmentId);
args = new Args(ssrsReportStr(WHSPickListShipping, Report));
args.record(whsShipmentTable);
args.parm(whsShipmentTable.LoadId);
contract = new clWHSPickListShippingContract();
controller = new WHSPickListShippingController();
controller.parmReportName(ssrsReportStr(WHSPickListShipping, Report));
controller.parmShowDialog(false);
controller.parmLoadFromSysLastValue(false);
controller.parmReportContract().parmRdpContract(contract);
controller.parmReportContract().parmRdpName(classStr(clWHSPickListShippingDP));
controller.parmReportContract().parmRdlContract().parmLanguageId(CompanyInfo::languageId());
controller.parmArgs(args);
controller.startOperation();
I don't know if I'm clear enough... But I've been looking for a fix for hours without success, so I thought I'd ask here. Is there a reason why this variable (which comes from the method parameter AifQueryBuilderArgs) would be empty?
I'm thinking your issue is with these lines (try removing):
controller.parmReportContract().parmRdpContract(contract);
controller.parmReportContract().parmRdpName(classStr(clWHSPickListShippingDP));
controller.parmReportContract().parmRdlContract().parmLanguageId(CompanyInfo::languageId());
The style I'd expect to see with your contract would be like this:
controller = new WHSPickListShippingController();
contract = controller.getDataContractObject();
contract.parmWhatever('ParametersHere');
controller.parmArgs(args);
And for the DataProvider clWHSPickListShippingDP, usually if a report is using a DataProvider, you don't manually set it, but the DP extends SRSReportDataProviderBase and has an attribute SRSReportParameterAttribute(...) decorating the class declaration in this style:
[SRSReportParameterAttribute(classstr(MyCustomContract))]
class MyCustomDP extends SRSReportDataProviderBase
{
// Vars
}
You are using controller.parmReportContract().parmRdpContract(contract); wrong, as this is more for run-time modifications. It's typically used for accessing the contract for preRunModifyContract overloads.
Build your CrossReference in a development environment then right click on \Classes\SrsReportDataContract\parmRdpContract and click Add-Ins>Cross-reference>Used By to see how that is generally used.
Ok, so now I feel very stupid for spending so much time on that error, when it's such a tiny thing...
The erronous line is that one :
controller.parmReportName(ssrsReportStr(WHSPickListShipping, Report));
Because WHSPickListShipping is the name of the AX report, but I renamed my custom report clWHSPickListShipping. What confused me was that my DataProvider class was executing as wanted.
I am trying to mock some methods that use the google-api-ruby-client to make some testing without actually calling the api. Authentication and client and activities methods are taken from the example found on the github page (see link above), which is why I skipped it here.
The method from the example is the following:
def activities
result = client.execute(
:api_method => plus.activities.list,
:parameters => {'collection' => 'public', 'userId' => 'me'}
)
return result.data
end
I previously tried to stub the client (even chained with the execute) methods, however this results in authorization requests for oauth, which the gem uses underneath followed by mocks for the plus.activities.list methods. Is there a way to directly mock client.exectute to return something useful while skipping the whole chain?
I am not sure that I understand your problem correctly, but maybe something a little bit crazy will work
I assume that your method is in Client model so maybe something like that will work
Client.stub_chain(:client, :execute).and_return(true)
Of course if you model have different name you have to adjust. I am not sure but you can give it a try
Checkout their spec helper:
https://github.com/google/google-api-ruby-client/blob/master/spec/spec_helper.rb
And how they do the tests:
https://github.com/google/google-api-ruby-client/blob/master/spec/google/api_client_spec.rb
I'm baffled why this works on my development server (using IIS Express) and not on the production server (Win2K8 R2 + IIS 7.5).
I have a very simple WebAPI controller method:
public HttpResponseMessage Get(string notificationType = "all", int skip=0, int take=25) {
Trace.WriteLine(String.Format("Hello, world! From NotifcationsController#Get notificationType={0} skip={1} take={2}", notificationType, skip, take));
Trace.WriteLine(String.Format("And furthermore, HttpContext.Current.Request[notificationType]={0}", HttpContext.Current.Request["notificationType"]));
Trace.WriteLine(String.Format("And finally, HttpContext.Current.Request.QueryString[notificationType]={0}", HttpContext.Current.Request.QueryString["notificationType"]));
...
}
On the development server at http://localhost:1398/api/notifications?notificationType=comments, things work. I see this in trace.axd:
Trace Information
Category Message From First(s) From Last(s)
Hello, world! From NotifcationsController#Get notificationType=comments skip=0 take=25
And furthermore, HttpContext.Current.Request[notificationType]=comments
And finally, HttpContext.Current.Request.QueryString[notificationType]=comments
But when hitting this controller at http://api.nameofmywebsite.com/api/notifications?type=comments I see this in trace.axd:
Trace Information
Category Message From First(s) From Last(s)
Hello, world! From NotifcationsController#Get notificationType=all skip=0 take=25
And furthermore, HttpContext.Current.Request[notificationType]=
And finally, HttpContext.Current.Request.QueryString[notificationType]=
...
Querystring Collection
Name Value
type comments
This seems very, very bizarre to me. Based on what's in trace.axd, it sure doesn't seem to be a routing issue... it's hitting the correct controller and action.
Why isn't the querystring parameter getting mapped to the parameter of the controller action in the production environment!?
For whatever it's worth, I'm using the same web.config on both development and server. I can't think what configuration differences would cause this difference...
I'm a moron.
This wasn't working because I was hitting "notifications?type=comments" on the production server and not "notifications?notificationType=comments"
The method parameter name has to match the querystring parameter name for binding to happen. I knew that, but didn't realize I was passing in the wrong querystring parameter name! What happened is that I changed the method parameter name a few weeks ago, forgot it in the meantime, and didn't realize the browser's autocomplete function supplied me with a history match that contained the old parameter name.
Here's my problem - I am using MvcMailer to create nicely formatted emails using Razor syntax, and it's a great tool to use for that!
The issue I'm running into is this - here's some syntax from my View for one of the emails i send:
<p>Click here to return to #ViewBag.IdeaName</p>
Whenever I try to run my unit tests, I get the following error message:
Can we send out email notifications for new comments?: System.ArgumentNullException : Value cannot be null.
Parameter name: httpContext
Stacktrace - shortened for brevity, relevant sections only:
at System.Web.Routing.RouteCollection.GetRouteData(HttpContextBase httpContext)
at Mvc.Mailer.MailerBase.CreateControllerContext()
at Mvc.Mailer.MailerBase.ViewExists(String viewName, String masterName)
at Castle.Proxies.Invocations.MailerBase_ViewExists.InvokeMethodOnTarget()
at Castle.DynamicProxy.AbstractInvocation.Proceed()
The issue is that my HttpContext is null - is there a straightforward way to unit test this MvcMailer method without having to mock everything from the controller context all the way down the route results?
You can take a look at the section titled Unit Test Your Mailers at the MvcMailer wiki All you need to do is, just mock out the PopulateBody method and then it will bypass the view rendering as a part of the testing. It should look something like the following:
_userMailerMock.Setup(mailer => mailer.PopulateBody(It.IsAny<MailMessage>(), "Welcome", null));
Hope this helps!
This syntax worked for me:
var userMailerMock = new Mock<UserMailer> {CallBase = true};
userMailerMock.Setup(mailer => mailer.PopulateBody(It.IsAny<MailMessage>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<Dictionary<string, string>>()));
You might want to mock the other overload as well (if the above doesn't help or just to be sure):
userMailerMock.Setup(mailer => mailer.PopulateBody(It.IsAny<MailMessage>(), It.IsAny<string>(), It.IsAny<Dictionary<string,string>>()));