I'm dealing with a problem I have in a Symfony 4 API functional tests. My functional tests consists in making requests to the API and analyze the response given. I've been working like this and works fine.
The problem comes with a new API method I'm implementing which needs the perform a request to an external service. I want to mock during my tests, but I don't know how can I create a mock that persists when the API receives the request from the functional test.
I've been thinking about something like create mocks which are always used in the test environment but I haven't found anything...
you can check in http-client service called url and if it compare your external api url return certain response, it will be look something like this:
$guzzleServiceMock = $this
->getMockBuilder(GuzzleHttp\Client::class)->disableOriginalConstructor()
->setMethods(['get'])
->getMock();
$guzzleServiceMock
->expects($this->any())
->method('get')
->with(
$this->stringContains('/external/api/route')
)
->willReturnCallback(
function ($uri, $options = []) {
return new Response(
200,
[],
'{"result": {
"status": "success",
"data": "fake data",
}}'
);
}
);
next step you will need to inject service into container, with this question you can look this repo, there are good examples of how this can be done: https://github.com/peakle/symfony-4-service-mock-examples/blob/master/tests/Util/BaseServiceTest.php
I'm not sure if I understand correctly, but if you'd like to mock an external API (meaning your application is connecting to another application on another server), one solution would be to actually lunch a mock server to replace your actual external server.
Either you implement such a mock server yourself or you use an existing solution such as http://wiremock.org/
Related
I have a playframework project that has reached beta/user testing.
For this testing we require test data to exist in the environment
I am looking for a way to automate this via scripts.
The best way will be via call's to the API passing the correctly shaped data based on the models in the project (thus dependant on the project not external).
Are there any existing SBT plugins that I could utilise that would be able to create the appropriate JSON and pass it to the API to setup the environment
Why do you need a plugin for this? I think what you want to do is to have a set of Json, then call the end-points and see what is the response from the back-end. In case of "setting up" based on a call that has a Json, you could use FakeRequest in your tests:
val application = newGuiceApplicationBuilder().build()
val response = route(application, FakeRequest(POST, "/end-point")).get
contentAsString(response) must include("where is Json")
In your test you can also test the response from the back-end and the Json you are feeding it:
Create a set of Json using Writes, based on a case class you are using in the back-end. You could also purposely create an invalid Json as well, that misses a field for example; or has an invalid structure.
Use Table driven testing and sending FakeRequest with the body/header containing your Json; and then checking it against the expected results.
I'm on the move, when I get home, I can write an example code here.
I have an API that I've written and now I'm in the middle of writing an SDK for 3rd parties to more easily interact with my API.
When writing tests for my SDK, it's my understanding that it's best not to simply call all of the API endpoints because:
The tests in the API will be responsible for making sure that the API works.
If the SDK tests did directly call the API, my tests would be really slow.
As an example, let's say my API has this endpoint:
/account
In my API test suite I actually call this endpoint to verify that it returns the proper data.
What approach do I take to test this in my SDK? Should I be mocking a request to /account? What else would I need to do to give my SDK good coverage?
I've looked to other SDKs to see how they're handling this (Stripe, Algolia, AWS), but in some cases it does look like they're calling a sandbox version of the actual API.
(I'm currently working with PHPUnit, but I'll be writing SDKs in other languages as well.)
I ended up taking this approach:
I have both unit tests AND integration tests.
My integration tests call the actual API. I usually run this much less frequently — like before I push code to a remote. (Anyone who consumes my code will have to supply their own API credentials)
My unit tests — which I run very frequently — just make sure that the responses from my code are what I expect them to look like. I trust the 3rd party API is going to give me good data (and I still have the integration tests to back that up).
I've accomplished this by mocking Guzzle, using Reflection to replace the client instance in my SDK code, and then using Mock Handlers to mock the actual response I expect.
Here's an example:
/** #test */
public function it_retrieves_an_account()
{
$account = $this->mockClient()->retrieve();
$this->assertEquals(json_decode('{"id": "9876543210"}'), $account);
}
protected function mockClient()
{
$stream = Psr7\stream_for('{"id": "9876543210"}');
$mock = new MockHandler([new Response(
200,
['Content-Type' => 'application/json'],
Psr7\stream_for($stream)
)]);
$handler = HandlerStack::create($mock);
$mockClient = new Client(['handler' => $handler]);
$account = new SparklyAppsAccount(new SparklyApps('0123456789'));
$reflection = new \ReflectionClass($account);
$reflection_property = $reflection->getProperty('client');
$reflection_property->setAccessible(true);
$reflection_property->setValue($account, $mockClient);
return $account;
}
When writing tests for the SDK you assume that your api DOES work exactly like it should (and you write tests for your api to assure that).
So using some kind of sandbox or even a complete mock of your api is sufficient.
I would recommend to mock your API using something like wiremock and then write your unit tests around that mock API to make sure everything works as desired.
This way when your production app with break, you can at-least make sure (by running unit tests) that nothing broken in your application side but there can be problem with actual API (i.e response format being changed).
I have a working hapi service, complete with hapi-swaggered and hapi-swaggered-ui. This is useful for many cases, but I want to add a build step to my CI which will be able to get the JSON generated by hapi-swaggered (which, if changed, would get compiled that into an .Net assembly that gets stored in a local proget).
I know that if I really wanted to, on my build server, I could start an instance of my server, curl to localhost:3000/swagger, kill the server, and proceed, but that seems a little risky (i.e., what if I have two builds running at the same time?).
Has anyone developed a way to directly call the hapi-swaggered API to get the raw JSON?
Well, that didn't take too much longer, but I think I found one solution. In this case, internals is my server. It does not auto-start if its loaded (required'ed) from another file, and the compose method is exposed to use hapi's Glue.compose to assemble the service. It seems that I can then use the inject method to simulate a call.
'use strict';
var internals = require('./');
internals.compose(function(err, server) {
server.inject({ method: 'GET', url: '/swagger' }, function (response) {
console.log(JSON.stringify(response.result));
process.exit();
});
});
If there's anything that I'm missing about this technique, I'd like to hear about it.
I'm following this article to mock response in dojo.
My mocker is very similar to the one in the article except this:
registry.register(/\/testIntern/, function (url, options) {
return when({
value: "Hello World"
});
In my understanding, this should map to any request that contains "/testIntern" on the address.
My testcase is quite simple:
// similar to example
var testRest= new Rest("/testIntern", true);
testRest("").then(lang.hitch(this, function (data) {
assert.deepEqual("Hello World", data.value, "Expected 'Hello World', but got" + data.value);
}));
It really should be quite simple. But when I run this test, I got 404 Not Found. It looks like the REST call in the test doesn't try to use the mocking service. Why?
You are generally correct in your thought that registering a URL with dojo/request/registry should pass anything referencing that URL via dojo/request through your handler.
Unfortunately, dojo/store/JsonRest uses the dojo/_base/xhr module which uses dojo/request/xhr directly, not dojo/request. Any registrations created with dojo/request/registry (and any setting of defaultProvider) will unfortunately be lost on JsonRest.
You might want to have a look at dstore - its Rest store implements the same server requests as dojo/store/JsonRest but it uses dojo/request instead of being hard-coded to a specific provider. (dojo/request defaults to dojo/request/xhr in browsers anyway, but can be overridden via dojoConfig.requestProvider.) dstore contains adapters for translating between dstore's API and the dojo/store API, if you need to use it with widgets that operate with the latter.
I'm attempting to mock the response of a dojo xhr request, but I haven't found a good solution.
Ideally, I'd like to see a solution similar to the jQuery mockjax plugin where I can set a specific call based on a url, e.g.:
$.mockjax({
url: '/restful/fortune',
responseTime: 750,
responseText: {
status: 'success',
fortune: 'Are you a turtle?'
}
});
My initial thought was to utilize the "/dojo/io/send" channel, but I haven't been able to get a modified response to be loaded after modifying the dojo Deferred object.
The other thought is to use a pass-through method that would determine if an actual xhr request should be made, e.g.:
function xhrRequest(xhrArgs) {
if(shouldMock) {
var fakeReturnJson = dojo.toJson({
howdy: "that's odd!",
isStrange: false
});
return fakeReturnJson;
} else {
dojo.xhr(xhrArgs);
}
}
Can someone tell me the best way to go about mocking dojo xhr calls?
Thanks!
It's an old question, but I think you should do your mocking using Sinon.js
However you will need to put the following:
has: { native-xhr2: false }
into your dojoConfig for it to work in 1.8
I haven't heard of any Dojo specific libraries similar to Mockjax. But what I think you could try is use Mockjax with Dojo. This should be pretty easy to do since all you'll have to do is use JQuery during development only for testing with Mockjax and then remove it once development is complete.
I use your second suggestion. Currently, I have a transport layer (simple js class) and 2 implementations (XhrTransport and MockTransport). I then switch in which I need without changing the widget code.
Widgets call the server with:
Controller.send(aServerCall);
where aServerCall is a simple value object with the server endpoint, params and callback.
This way, you can add nice things to the controller that will apply to all server calls (such as logging, analytics, generic error handling...) and also mock out the entire server when doing unit tests.
For the MockTransport, I simply return canned json data from static .js files in the format that the widget expects.