I am reading the documentation for converting to v107+. I'm currently using v108. In the documentation, for mocking, it says to do this:
var client = new RestClient(...) { ConfigureMessageHandler = _ => mockHttp };
But apparently v108 no longer works this way and the documentation has not been updated. Does v108 support setting the MessageHandler? My company uses SonarQube for unit test code coverage and we are missing several hundred lines of coverage without this capability.
The RestClient class never had a property called ConfigureHttpMessageHandler.
The top of the documentation page has the correct code:
Indeed, the code in the "Mocking" section is wrong; it's just a typo.
Related
I'll apologize up-front for not being able to post actual code that exhibits this possible issue as it is confidential, but I wanted to see if anyone else might have observed the same issue. I looked in the project for any open/closed issues that might be like this but did not notice any.
I noticed that when I use the Karate testParallel runner (which we have been using for a while now), that every GET, POST, DELETE request issued gets called 2x, observed in the karate logs.
It doesn't matter if the request is being directly called in a scenario or indirectly from another feature file via call/callonce.
When I do not use the Karate testParallel runner only a single request is made.
I noticed this when performing a POST to create a a data source in our application. When I went to the applications UI to verify the new data source was created, I saw 2 of them. This lead me down the path to research further what might be happening.
To possibly rule out our API was doubling up on the data source creation, a data source was created via a totally different internal tool and only 1 data source got created. This lead me back to Karate to see what might be causing the double creation and observing the issue.
Bottom-line is that I think the parallel runner is causing requests to occur twice.
Using Karate v0.9.3
When using the parallel test runner, multiple POST's get executed. The code below uses the Post Test Server V2 to submit a POST to and you can see that 2 posts are submitted.
Note the test runner is NOT using the #RunWith(Karate.class) annotation and using the junit:4.12 transient dependency from karate-junit4:0.9.3
Here is a Minimal, Complete and Verifiable example that demonstrates the issue:
Feature file:
Feature: Demonstrates multiple POST requests
Scenario: Demonstrates multiple POST requests using parallel runner
* def REQUEST = {type: 'test-type', name: 'test-name'}
Given url 'https://ptsv2.com/t/paowv-1563551220/post'
And request REQUEST
When method POST
Then status 200
Parallel Test Runner file:
import com.intuit.karate.Results;
import com.intuit.karate.Runner;
import org.junit.Test;
public class ApiTest {
#Test
public void testParallel() {
Results results = Runner.parallel(getClass(), 5, "target/surefire-reports");
assertTrue(results.getErrorMessages(), results.getFailCount() == 0);
}
}
After running this feature, using the parallel runner, go to https://ptsv2.com/t/paowv-1563551220/post and observe the multiple POST's.
Comment out the #Test JUnit annotation in the parallel runner and re-run feature and notice only 1 POST is requested, as expected.
When I originally posted this question I was definitely using a JUnit 4 Parallel Execution class without the #RunWith(Karate.class) annotation. This was in conjunction with the com.intuit.karate:karate-junit4 dependency and I was definitely getting multiple POST requests sent.
In revisiting this issue, I recently updated my dependency to use com.intuit.karate:karate-junit5 and updated to use a JUnit 5 Parallel Execution class (again, without the #RunWith(Karate.class) annotation) and I'm happy to report that I'm no longer seeing multiple POST requests.
You most likely are using the #RunWith(Karate.class) annotation when you are not supposed to. This is mentioned in the docs. Fortunately this confusion will go away when everyone switches to JUnit 5.
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'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.
Restlet looks cool, but Im sorry, I'm just banging my head all day due to lack of documentation on a simple client.
I've managed to crib some useful stuff from
http://restlet.org/learn/guide/2.1/core/resource/client
But there is just nothing that actually works as a full download (which would be nice). For example is the Customer here a pojo only ? or must it implement Serializable (I think it must).
My specific issue is as follows:
I have some code which makes a call to a URL and gets back this:
{"result":"success","data":{"last_local":{"value":"889.66000","value_int":"88966000","display":"$889.66","display_short":"$889.66","currency":"USD"},"last":{"value":"889.66000","value_int":"88966000","display":"$889.66","display_short":"$889.66","currency":"USD"},"last_orig":{"value":"889.66000","value_int":"88966000","display":"$889.66","display_short":"$889.66","currency":"USD"},"last_all":{"value":"889.66000","value_int":"88966000","display":"$889.66","display_short":"$889.66","currency":"USD"},"buy":{"value":"889.00000","value_int":"88900000","display":"$889.00","display_short":"$889.00","currency":"USD"},"sell":{"value":"889.66000","value_int":"88966000","display":"$889.66","display_short":"$889.66","currency":"USD"},"now":"1388846889233438"}}
The bit I'm struggling with, is the MAGIC that happens as follows:
ClientResource cr = new ClientResource(….); // fine
IDataStruct resource = cr.wrap(IDataStruct.class); // <---- Magic here, but fine at Runtime.
if(cr.getResponse().getStatus().isSuccess()) // fine
{
PriceObject price = resource.retrieve();//<--- get to this line but then everything blows up because no converter is found. I can't use Jackson because GAE does not like it
}
The question is, what should the IDataStruct interface look like ??
Will.
Customer in the example is indeed a POJO. Depending on the converter you would use, you can make it serializable or not. BTW, Jackson should work on GAE, which issue did you encounter exactly?
IDataStruct should be a Java interface annotated with Restlet API annotations such as #Get, #Post, etc.
Regarding the user guide, you can find the edited version in GitHub, where I just fixed some of the broken links (will be published soon on Restlet.org):
https://github.com/restlet/restlet-sites/blob/master/modules/org.restlet/learn/guide/2.1/introduction/first-steps/first-client.md
I'am obviously new to Google Apps Script, nevertheless I have some experience in coding in C, PHP and Java. Since we would like to create a small CRM in our company with Google Apps Script, we need to create an application with a form available on Google Sites. I've been searching an answer for this problem a long time, I haven't unfortunately found any answer. I have a code like this:
var klienci_id = new Array(100);
var klienci_nazwa = new Array(100);
var klienci_adres = new Array(100);
var klienci_osoba = new Array(100);
var klienci_telefon = new Array(100);
var klienci_email = new Array(100);
function doGet(e) {
var app = UiApp.createApplication();
// hello world label
var helloworldLabel = app.createLabel("I love Apps Script!").setStyleAttribute("fontSize","16px");
// add the label to the app container
app.add(helloworldLabel);
return app;
}
function main() {
var klienci = SpreadsheetApp.openById("0ArsOaWajjzv9dEdGTUZCWFc1NnFva05uWkxETVF6Q0E");
var kuchnia_polska = klienci.getSheetByName("Kuchnia polska");
var dane = kuchnia_polska.getRange("D7:F22");
doGet();
}
And everytime I try to publish it and enter the given link I get the error "Unknown macro doGet". I know this is a common problem when somebody doesn't use doGet() function but I do - and it still doesn't work. I also believe that Google should create a thorought documentation on Google Apps Script, which would work the way the Unix manual does, since I just cannot get through all these strange pages of goddamn help :) It's neither a Windows help, nor a good manual ;)
Regards,
Kamil
I have a suspicion that you made a "version" once, published the app, went to the "real" link and not the "development" link, and then added the doGet() function. When you make a version, it freezes the code at that time. The version that the app is published at is the version of the code that will run at the "real" link (what you give users), which allows you to keep editing the code without disturbing existing users of your app. There is a special "development" link given to you in the publish dialog that always refers to the most recent version of the code, but which will only work for you and no one else.
I'm affraid there is a little misunderstanding on your side concerning the use of the 'doGet()' function. When you want to run an application as a webapp, the doc says indeed that it must contain a doGet function but what it doesn't say explicitely is that this function is supposed to be the starting point of the whole app, ie the function that the url will call in the first place. So it doesn't make much sense to have the doGet function called from a so called "main" function since the "main" function is not the main function...
I cannot imagine right now a situation where some function calls the doGet function since every function in the script is called initially (directly or indirectly) from this doGet function.... in fact the 'end' of any other function in the script 'returns' to the doGet initial function. Well this is maybe not absolutely true in every case but it gives you the general idea about how it works.
I'm hoping this is clear enough and, to return to your code snippet, if you remove the doGet(e) call, it will ideed show a nice "I love Apps Script!" but it will never do anything else, certainly not see the "main" function.
I've copied your code here https://script.google.com/macros/d/MJ80AK8t7kbgDcC-NaLPYvH797_hv7HHb/edit?template=app&folder=0AKGkLMU9sHmLUk9PVA
and when deployed as a web app appears to work https://script.google.com/macros/s/AKfycbxOiaukLt7P4pIm7bms7aU16uEo6FuZ-MNOh0tSqUwr/dev
Only thing I can think of is there is something else in your code not copied into the snippet that is throwing the exception.
[Just before the GUI Builder was published I came up with Creating a framework for custom form interfaces using Google Apps Script which might help you with your project]
Thank you both for help. Serge, yes, it's really not obvious what the structure of Google Apps Scripts should be. They are based on JavaScript, however, due to lack of HTML in the code they have completely different flow - so naturally, there has to be a main function which is executed first. And of course in every programming environment it has to have a different name to make it more distinguishable ;-)
I created a new copy of my application, not changing the code completely - deployed it and it works beautifuly. Since I haven't changed anything in access options, it's quite strange that two applications with the same code and the same options don't give the same result. I think it may be a kind of the environment flaw, maybe someone from Google should look at this :)
Here's the link to the script, I've set access to "Anyone with the link".
https://script.google.com/a/macros/foodbroker.pl/s/AKfycbwk2IM-rIYLhQl6HOlbppwGOnw4Ik_kH7ixbaSNVxIE-QR7cq8/exec