Unit tests for simple REST client [duplicate] - rest

This question already has answers here:
Need some advice for trying to mock a .NET WebClient or equivalent
(2 answers)
Closed 6 years ago.
Let's assumed that i've got simple method which gets some data from REST service. Method looks like:
public string GetDataFromRest(string uri) {
string result = String.Empty;
using(WebClient web = new WebClient()) {
result = web.DownloadString(uri);
}
return result;
}
So, now i want to create unit test for this method. I don't want to use external REST service but i want fake response from any URI without real conecting to service. Something like every execute of GetDataFromRest(uri) in Unit Test -> always returns some XML.

As the posted answer goes into some detail, part of your problem is you have a dependency on the WebClient class.
A sample wrapper for WebClient could look like:
public interface IWebClient
{
string DownloadString(string address);
}
public class WebClientWrapper : IWebClient
{
public string DownloadString(string address)
{
using(WebClient web = new WebClient()) {
return result = web.DownloadString(uri);
}
}
}
public class MyClass
{
private readonly IWebClient _webClient;
public MyClass(IWebClient webClient)
{
_webClient = webClient;
}
public string GetDataFromRest(string uri)
{
return _webClient.DownloadString(uri);
}
}
Now of course going this route means WebClientWrapper can be unit tested with a "less real" URI or what that you specifically control. I've only implemented one method of the WebClient, but this externalizes the dependency within GetDataFromRest from a real URI, as you can now mock the return data. This also helps in that anything else you need a WebClient for, you can now use the wrapper class, and easily mock the returned data, as you are now programming to an interface, rather than a concretion.

Related

WireMock does not transform response

I'm having an issue using WireMock, I've extended ResponseTransformer and implemented all required methods, it looks like this:
public class TempResponseTransformer extends ResponseTransformer {
#Override
public Response transform(Request request, Response response, FileSource fileSource,
Parameters parameters) {
return Response.Builder.like(response).but().status(404).body("1").build();
}
#Override
public boolean applyGlobally() {
return false;
}
#Override
public String getName() {
return "temp-response-transformer";
}
}
Now I want to apply this particular transformer to one of the stubs, that I wrote, stub looks like this:
private static void initTempStub() {
stubFor(post(urlPathEqualTo("/api/v1/temp"))
.withHeader("AccessToken", matching("[a-zA-Z0-9]+"))
.withHeader("CliendID", matching("[a-zA-Z0-9]+"))
.withHeader("ClientSecret", matching("[a-zA-Z0-9]+"))
.willReturn(aResponse()
.withTransformers("temp-response-transformer")));
}
When I start service and perform post calls I do see that transformer is applied, however responses actually not being transformed.
I've tried to apply transformer in config section when starting service as well, but it doesn't help.
So my question is how should I apply ReponseTransformer correctly so it would transform my responses?
Ok, think I've figured it out.
Here is an issue(?) with WireMock that I was able to figure out while looking at the internals, here is how I passed config:
new WireMockServer(wireMockConfig()
.extensions(TempResponseTransformer.class)
.options().notifier(new ConsoleNotifier(true)))
And an issue with this code is when you call options() from wireMockConfig it would create new instance of WireMockConfig, so I had to extract this config into separate piece of code like this:
var wireMockConfig = new WireMockConfiguration();
wireMockConfig
.extensions(SamplesResponseTransformer.class)
.notifier(new ConsoleNotifier(true));

Xamarin forms Rest Client [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 5 years ago.
Improve this question
Anybody suggest me a good Rest client that i can use for my xamarin forms cross platform application ?
(Android and Windows Phone)
Thanks in advance.
That's a very open question.
Anyway my favorite:
Refit
Updated Removing the other two libraries that even though you can do REST with them they are not considered REST clients but HTTP clients.
You can you Microsoft HTTP Client Libraries.
Then, you define a RestService class that contains a HttpClient instance:
public class RestService : IRestService
{
HttpClient client;
public RestService()
{
client = new HttpClient();
client.MaxResponseContentBufferSize = 256000;
}
// example for GET request
public async Task<List<TodoItem>> RefreshDataAsync()
{
var uri = new Uri(string.Format(Constants.RestUrl, string.Empty));
var response = await client.GetAsync(uri); // make a GET request
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
// handle response here
}
}
}
You should follow this article:
https://developer.xamarin.com/guides/xamarin-forms/cloud-services/consuming/rest/
I do not know if there are simple implementation for this purpose but you have to write your own parsers, senders, receivers according to your needs. I would give you a little example :) First of all i have a base class for my generic restCall
public abstract class BaseDto
{
public string Id {get;set;}
}
than write your business objects like
public class UserDto : BaseDto
{
public string Name {get;set;}
//etc.
}
public class SavedUserDto : BaseDto
{
public int Id {get;set;}
public string Name {get;set;}
//etc.
}
than write a simple http caller
public string Post<T>(string url, T entity) where T : BaseDto
{
//here u will write a HttpClient and send receive json. U can find examples on the net. Of course use Newtonsoft for json convertions
}
Than write a generic method to call this post method, of course you will send a baseDto and receive a baseDto too :)
public K Call<T, K>(
string restApiPath,
T entity) where T : BaseDto where K : BaseDto
{
var response = Post(restApiPath, entity);
//you can handle errors, auth faults etc. here.
return JsonConvert.DeserializeObject<K>(response);
}
than in your code just do
var savedUser = Call<UserDto,SavedUserDto>("127.0.0.1/user/save",new UserDto{Name="John"})
Hope it can give you an idea. Than when you add a new service method on your rest api, you can call it just with a single line of code (of course you have to write new business DTO's - aka data transfer objects:))
Of course all this POST and CALL methods on different classes. Do not forget, a class must do only one thing. So POST method owner class (let's call it HttpCaller) will only send the Dto to the server and get the answer. CALL method owner class (lets call it MyService) will get the resut and process it etc.
You can use HttpClient. It is good. get from nuget System.Http.Net

Servicestack (rest) incorrect WSDL with mono

I've written a simple self-hosted (in a ConsoleApplication) rest service with service stack 3.9.70.
using System;
using System.Runtime.Serialization;
// service stack support
using ServiceStack.ServiceHost;
using ServiceStack.WebHost.Endpoints;
namespace HelloWorldConsole
{
namespace DTO
{
[DataContract(Namespace = "http://localhost:8080/types")]
[Route("/hello/{Name}")]
class Hello : IReturn<HelloResponse>
{
[DataMember]
public string Name { get; set; }
}
[DataContract(Namespace = "http://localhost:8080/types")]
class HelloResponse
{
[DataMember]
public string Response { get; set; }
}
}
class HelloService : IService
{
public Object Any(DTO.Hello request)
{
return new DTO.HelloResponse { Response = "Hello " + request.Name };
}
}
public class HelloHost : AppHostHttpListenerBase
{
public HelloHost()
: base("Hello Service Self-Host",
typeof(HelloService).Assembly)
{ }
public override void Configure(Funq.Container container)
{
SetConfig(new EndpointHostConfig
{
DebugMode = true,
WsdlServiceNamespace = "http://localhost:8080/",
WsdlSoapActionNamespace = "http://localhost:8080/",
SoapServiceName = "HelloService"
});
}
}
class MainClass
{
public static void Main (string[] args)
{
string listenOn = "http://localhost:8080/";
HelloHost host = new HelloHost ();
host.Init ();
host.Start (listenOn);
Console.WriteLine ("AppHost created at {0} on {1}",
DateTime.Now, listenOn);
Console.ReadKey ();
}
}
}
Under Windows the generated WSDL is good, and if I try to create a client application and add a web reference to the soap service on localhost, I'm able to call Hello.
If I run the same code under Linux using Mono, the generated WSDL does not contain the types defined inside the DTO namespace. If I try to add a web service reference on a client, I'm not able to exploit hello method.
At this link I've read that by default the same ServiceStack Console app binary runs on both Windows/.NET and Mono/Linux as-is. I've tried to launch the binary under windows; the service runs but the generated WSDL is incorrect (without types defined in DTO namespace).
I use mono 2.10.8.1.
Does anyone have any suggestion?
I also have another question. If I use new version Servicestack last release (4.0.33) I'm not able to exploit soap endpoint.
At this link I've read that SOAP endpoints are not available when hosted on a HttpListener Host. Is it a feature introduced with new version 4.0?
Isn't there the posbility to exploit soap endpoints with servicestack releases higher than 3.9?
Any help is appreciated.
Mono has a weak and partial WCF/SOAP support which will fail to generate WSDLs for many non-trivial Service definitions. This situation may improve in the near future now that Microsoft has Open Sourced .NET server libraries, but in the interim I recommend avoiding Mono if you want to use SOAP.

Using WebServiceGatewaySupport to handle requests to multiple webservices

I'm using spring-ws-core to build a SOAP client. For this I'm extending WebServiceGatewaySupport to make the service calls.
public class WeatherClient extends WebServiceGatewaySupport {
...
public WeatherResponse getCityForecastByZip(String zipCode) {
GetCityForecastByZIP request = new GetCityForecastByZIP();
request.setZIP(zipCode);
GetCityForecastByZIPResponse response = (GetCityForecastByZIPResponse) this.getWebServiceTemplate().marshalSendAndReceive(request,
new SoapActionCallback("http://ws.cdyne.com/WeatherWS/GetCityForecastByZIP"));
return response;
}
...
}
Spring configuration is pretty straightforward
#Configuration
public class WebServicesConfiguration {
private static final String WEATHER_SERVICE_DEFAULT_URI = "...";
#Bean(name = "servicesMarshaller")
public Jaxb2Marshaller servicesMarshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("some.package");
return marshaller;
}
#Bean
public WeatherClient weatherService(#Qualifier("servicesMarshaller") Jaxb2Marshaller marshaller) {
WeatherClient client = new WeatherClient(WEATHER_SERVICE_DEFAULT_URI);
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
return client;
}
}
This works just fine for a single web service. Now, suppose that I have many similar web services, but each one has it's own .wsdl specification and URI. I know that I can make a service call through the spring WebServiceTemplate and specify the URI to use. So my idea was to use a single WebServiceGatewaySupport to handle all the calls to the different services. In each call, I would pass the soap action, the corresponding request, if any, and the web service URL. My application is suppose to run in a multi-threaded environment.
Is this a good practice to use a single WebServiceGatewaySupport to handle concurrent calls to different URIs?
Looking to the WebServiceGatewaySupport source code, the short asnwer: yes, it is OK to use it for different URLs, as well as the underlying WebServiceTemplate is thread-safe.
Your implementation will be thread-safe too, if you don't save some state between requests.

Jackson and REST Android Annotations: Deserialize JSON Array of Objects

I have a REST service which returns data that looks like this:
[
{ bookmark object json here },
{ bookmark object json here },
{ bookmark object json here },
...
]
My REST client class looks like this:
#Rest(rootUrl = Constants.ApiConfig.API_ROOT, converters = {MappingJackson2HttpMessageConverter.class})
public interface RestApiClient {
#Get("/bookmark/read?id={identifier}")
public BookmarkList getBookmarks(String identifier);
}
BookmarkList looks like this:
public class BookmarkList {
List<Bookmark> bookmarks;
#JsonValue
public List<Bookmark> getBookmarks() {
return bookmarks;
}
#JsonCreator
public void BookmarkList(#NotNull List<Bookmark> bookmarks) {
this.bookmarks = bookmarks;
}
}
However, when I utilize this setup, I get the following error:
Could not read JSON: Can not deserialize instance of com.whatever.entity.BookmarkList out of START_ARRAY token
What I want is something like the EventList example at https://github.com/excilys/androidannotations/wiki/Rest-API#get, but that doesn't seem to work for me out of the box.
Is there a way to get this working?
Ho... We have to update this part of documentation. The wrapper solution works but doesn't fit APIs.
If you're looking at the generated code for #Get("url") MyReturnedType testService(), you should see something like this :
return restTemplate.exchange(rootUrl.concat("url"), //
HttpMethod.GET, //
null, //
MyReturnedType.class, //
urlVariables)//
.getBody();
The returned class is injected as a parameter of exchange call. In case of generics collection (like List<MyReturnedType>), we can't inject List.class because of type checking in the return of exchange method.
However, you should be able to use this little trick in your #Rest annotated method :
public class BookmarkList extends List<Bookmark> {
}
I think I misunderstood the example at https://github.com/excilys/androidannotations/wiki/Rest-API#get. I think the array still must be wrapped inside a JSON object in that example (It'd be nice if they included example JSON data).
The data the service I'm connecting to does not return an object wrapping the array like that, so, I altered the REST client to look like this:
#Rest(rootUrl = Constants.ApiConfig.API_ROOT, converters = {MappingJackson2HttpMessageConverter.class})
public interface RestApiClient {
#Get("/bookmark/read?id={identifier}")
public ArrayNode getBookmarks(String identifier);
}
And I wrote a method in another class to iterate the ArrayNode and build the bookmarks:
public List<Bookmark> getBookmarks(Content content) {
ArrayList<Bookmark> bookmarks = new ArrayList<Bookmark>();
ArrayNode bookmarksData = apiClient.getBookmarks(content.getAcid());
for(JsonNode bookmarkData : bookmarksData) {
Bookmark bookmark = objectMapper.convertValue(bookmarkData, Bookmark.class);
bookmarks.add(bookmark);
}
return bookmarks;
}
So it's not as convenient (I had to write more code myself), but I got it working.