Calling WebAPI in UnitTest TestInitialize - unit-testing

im trying to write a UnitTest for a WebAPI and EF
Im trying to add Data do the database in den TestInitialize, but it didnt work. When i do the same command in a Console Applications, it works.
Is there a different in calling that webapi for tests?
[TestInitialize]
public void CreateEntityObjects()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:60609/");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Department dep1 = new Department() { Id = Guid.NewGuid(), Name = "IT" };
client.PostAsJsonAsync("api/Department", dep1);
}
Edit:
So i still just do the initialize no cleanup (later). I was looking manually if there is some data in the database. But no data, no Error, nothing.

You may try looking at the result property of the request:
var response = client.PostAsJsonAsync("api/Department", dep1).Result;
and then look at what does the server return:
string responseContent = response.Result.Content.ReadAsStringAsync().Result;
Now analyze the responseContent variable to see what possible error message you might have gotten from the server. Also you probably want to self-host your Web API in the unit test before sending an HTTP request to it, otherwise your API might not even be started.

Related

ASP.Net Core XUnit Integration Testing when Two Factor Authenication is enabled

I've developing an Angular web application using ASP.Net Core 3.1 for the API.
So far, I've written some integration unit tests using a Custom WebApplicationFactory to create the test server.
All tests use the HttpClient to make GETs and POSTs to the API running under the Custom WebApplicationFactory. Most of these tests initially perform a login to obtain a token to use for subsequent requests.
I'd like to add Two Factor Authentication to the application, but this will inevitably break any tests, as they aren't able to get hold of the six digit code which would be sent via email.
Here is what a test currently looks like, without MFA being implemented.
Is there a way that the test can be given the MFA code so that it can continue to perform tests?
Do I simply need to seed a user that does not have MFA enabled?
I actually want all users to have MFA enabled in production.
Many thanks
using Xunit;
using System.Threading.Tasks;
using MyCompany.ViewModels.Authentication;
using MyCompany.StaffPortal.Tests.Shared;
using StaffPortal;
using Newtonsoft.Json;
using MyCompany.ServiceA.ViewModels;
using System.Collections.Generic;
using System.Net.Http;
namespace MyCompany.Tests.StaffPortal.ServiceA
{
public class ExtensionsControllerTests : TestBase
{
public ExtensionsControllerTests(CustomWebApplicationFactory<Startup> factory) : base(factory)
{
}
[Fact]
public async Task Test_GetExtensions()
{
//This line creates a new "web browser" and uses the login details provided to obtain and set up the token so that we can request information about an account.
HttpClient httpClient = await CreateAuthenticatedHttpClient("abcltd1#MyCompany.com", "test", 1);
//Perform any work and get the information from the API
//Contact the API using the token so check that it works
var getExtensionsResponse = await httpClient.GetAsync("/api/ServiceA/extensions/GetExtensions");
//Check that the response was OK
Assert.True(getExtensionsResponse.StatusCode == System.Net.HttpStatusCode.OK, "GetExtensions did not return an OK result.");
//Get and Convert the Content we received into a List of ServiceAExtensionViewModel, as that is what GetExtensions sends back to the browser.
var getExtensionsResponseContent = await getExtensionsResponse.Content.ReadAsStringAsync();
List<ServiceAExtensionViewModel> extensionList = JsonConvert.DeserializeObject<List<ServiceAExtensionViewModel>>(getExtensionsResponseContent);
//Check the information received matches our expectations
Assert.True(extensionList.Count == 2);
Assert.True(extensionList[0].PropertyA == 123);
Assert.True(extensionList[0].PropertyB == 0161);
Assert.True(extensionList[0].PropertyC == true);
}
}
}
Here is the content's of CreateAuthenticatedHttpClient() for reference.
protected async Task<HttpClient> CreateAuthenticatedHttpClient(string username, string password, int companyAccountId)
{
var httpClient = _factory.CreateClient(
new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false
});
//Create the Login information to send to the server
var loginInformation = new LoginRequestModel
{
Username = username,
Password = password,
ReturnUrl = ""
};
//Convert it into Json which the server will understand
var validLoginRequestJson = ConvertToJson(loginInformation);
//Send the Json Login information to the server, and put the response we receive into loginResponse
//In the code below, httpClient is like a web browser. You give it the
var loginResponse = await httpClient.PostAsync("/api/authenticate", validLoginRequestJson);
//Check the loginResponse was a CREATED response, which means that the token was made
Assert.True(loginResponse.StatusCode == System.Net.HttpStatusCode.Created, "New Token was not returned.");
//Check the response is identified as being in Json format
Assert.Equal("application/json; charset=utf-8", loginResponse.Content.Headers.ContentType.ToString());
//Next we have to convert the received Json information into whatever we are expecting.
//In this case, we are expecting a AuthenticationResponseViewModel (because that's what the API sends back to the person trying to log in)
//First we get hold of the Content (which is in Json format)
var responseJsonString = await loginResponse.Content.ReadAsStringAsync();
//Second we convert the Json back into a real AuthenticationResponseViewModel
AuthenticationResponseViewModel authenticationResponseViewModel = JsonConvert.DeserializeObject<AuthenticationResponseViewModel>(responseJsonString);
//Now we take the Token from AuthenticationResponseViewModel, and add it into the httpClient so that we can check the Token works.
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authenticationResponseViewModel.token);
httpClient.DefaultRequestHeaders.Add("CompanyId", companyAccountId.ToString());
return httpClient;
}

simple azure web service, http404 error on publish when adding /dowork to URL

I am trying my first web app service using Azure services. I've created it in VS, and it works locally. All it does it return a string that says "hello user" is JSON.
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service1
{
// To use HTTP GET, add [WebGet] attribute. (Default ResponseFormat is WebMessageFormat.Json)
// To create an operation that returns XML,
// add [WebGet(ResponseFormat=WebMessageFormat.Xml)],
// and include the following line in the operation body:
// WebOperationContext.Current.OutgoingResponse.ContentType = "text/xml";
[OperationContract]
[WebGet(UriTemplate = "/DoWork")]
public string DoWork()
{
// Add your operation implementation here
return "hello user";
}
// Add more operations here and mark them with [OperationContract]
}
}
Problem is when I publish it, says successful. I can see it running on portal.
When I goto published site I get the standard THIS WEB APP HAS BEEN SUCCESSFULLY CREATED, but... when I add the /DoWork to the URL I get HTTP error 404.
I know I must be missing something simple...
any ideas?
you're missing the name of the service. In your case would be something like:
http://engineappservicev001.azurewebsites.net/something.svc/dowork
More info in here:
http://www.codeproject.com/Articles/571813/A-Beginners-Tutorial-on-Creating-WCF-REST-Services

Cannot call web api 2 post method with int parameter in URL in Unit Test using Http server

Please ignore the spelling mistake, I cannot copy code so I have typed the whole thing and changed name of controller and method.
WEB API 2
Controller:
// Controller name is Test
public HttpResponseMessage Method1(int param1) // Post method
{
// return string
}
If I create an object of controller in test case then it is working fine. But if I want to test in localhost using following code:
Unit Test:
public void Method1Test()
{
HttpResponseMessage response;
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}");
HttpServer server = new HttpServer(config);
using(var client = new HttpClient(server))
{
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://localhost:5022/api/test?param1=1");
request.Content = new ObjectContent<int>(param1, new JsonMediaTypeFormatter());
response = client.SendAsync(request, CancellationToken.None).Result;
};
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
Now, my test case is failing. I used the same code in different project and it worked. May be it is the way I am trying to call Post method. Is this the right way to call post method with Int parameter in URL?
In help page, under API column it shows:
POST api/test/param1={param1}
Also I have put some stop point in actual service I am cursor is not stopping at that point. Why?
If I want to call the same service from browser, what URL should I pass? Is it -
http://localhost:5022/api/test?param1=1
Or something else?
I figured it out. Following is the correct unit test method but this has some extra information which I have not provided earlier i.e., passing object as an input for the service.
private void Method1Test(ObjectClass obj)
{
HttpResponseMessage response = null;
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}");
HttpServer server = new HttpServer(config);
using (var client = new HttpClient(server))
{
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://localhost:5022/api/test/1");
request.Content = new ObjectContent<ObjectClass>(obj, new JsonMediaTypeFormatter());
response = client.SendAsync(request, CancellationToken.None).Result;
};
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
So the correct URL that I was looking for was
http://localhost:5022/api/test/1
Sorry, It took long to post this answer. This method is working like a charm for more then 2 years.

Unable to set headers in apex web service callouts in salesforce

I'm currently trying to call Amazon Product Retail Web Service in Salesforce.
As I mentioned in
Getting WSDL parse error while generating Apex code from WSDL in Salesforce
I was initially unable to generate apex stub class, but I followed the method suggested by #Ballinger and created apex class. I wrote an apex class to use that stub and to set request parameters. The class i wrote is as follows
public class AmazonProductStubNew
{
public static void getResults()
{
System.Debug(' getResults start ');
AmazonWS.AWSECommerceServicePortUS stub = new AmazonWS.AWSECommerceServicePortUS();
stub.inputHttpHeaders_x = new Map<String,String>();
stub.inputHttpHeaders_x.put('AWSAccessKeyId','MyAmazonAWSAccessKeyId');
stub.inputHttpHeaders_x.put('Timestamp','2012-11-28T12:11:30Z');
stub.inputHttpHeaders_x.put('Signature','Encrypted Secret Code');
String MarketplaceDomain = '';
String AWSAccessKeyId = 'MyAmazonAWSAccessKeyId';
String AssociateTag = '';
String XMLEscaping = '';
String Validate = '';
AmazonWS.ItemSearchRequest Shared = new AmazonWS.ItemSearchRequest();
Shared.SearchIndex = 'DVD';
AmazonWS.ItemSearchRequest[] Request = new AmazonWS.ItemSearchRequest[1];
Request[0] = new AmazonWS.ItemSearchRequest();
Request[0].Title = 'Inception';
AmazonWS.ItemSearchResponse_element response = stub.ItemSearch(MarketplaceDomain,AWSAccessKeyId,AssociateTag,XMLEscaping,Validate,Shared,Request);
AmazonWS.Items_element[] localItems = response.Items;
System.Debug(localItems[0].TotalResults);
}
}
Even though I've added HTTP headers to stub, I'm not getting it in XML Request message
XML Request is as follows
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Header />
<env:Body>
<ItemSearch xmlns="http://webservices.amazon.com/AWSECommerceService/2011-08-01">
<MarketplaceDomain>
</MarketplaceDomain>
<AWSAccessKeyId>MyAWSAccessKeyId</AWSAccessKeyId>
<AssociateTag></AssociateTag>
<XMLEscaping></XMLEscaping>
<Validate></Validate>
<Shared><SearchIndex>DVD</SearchIndex></Shared>
<Request><Title>Inception</Title>
</Request></ItemSearch>
</env:Body></env:Envelope>
Since headers are not there in SOAP Request, There is a SOAP fault asking for Signature from Amazon Server.
As you can see, I'm new to Salesforce Apex. I followed the steps in
http://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm#StartTopic=Content/apex_web_services_wsdl2apex.htm#http_header_support
to set the headers.
Any idea on why the header isn't getting added?
P.S I added headers manually and tried in SOAP UI, I'm getting proper response.
Thanks :)
I think you're using wrong functions :) (question is indeed confusing).
SOAP (or generally HTTP) communication consists of sending headers and actual message (payload if you like). Headers are short text thingies, message is often a giant XML.
Your code is setting HTTP headers (which are used in web communication to authenticate, provide info about your browser, preferred languages, set cookies, return status codes like 404 page not found...) Please don't be offended with the "for dummies" but I realize the wikipedia article is a bit too much, this might be simpler: http://net.tutsplus.com/tutorials/other/http-headers-for-dummies/
And what I suspect Amazon's webservice wants is just some fields inside the <env:Header>...</env:Header> tag? Just check the generated apex code for existence of subclass called "Header" (you can also search for the variable names like "Signature". This is going to be a total wild guess but I think you'll have to write something like that:
AmazonWS.AWSECommerceServicePortUS stub = new AmazonWS.AWSECommerceServicePortUS();
AmazonWS.Header h = new AmazonWS.Header();
h.AWSAccessKeyId = 'MyAmazonAWSAccessKeyId';
h.Timestamp = '2012-11-28T12:11:30Z';
h.Signature = 'Encrypted Secret Code';
stub.Header = h; // plug it into the request
// create and plug other required tags
AmazonWS.ItemSearchRequest Shared = new AmazonWS.ItemSearchRequest();
Shared.SearchIndex = 'DVD';
AmazonWS.ItemSearchRequest[] Request = new AmazonWS.ItemSearchRequest[1];
Request[0] = new AmazonWS.ItemSearchRequest();
Request[0].Title = 'Inception';
// ...
Now, to make it more confusing you might still have to use a HTTP header, there's a special one called SOAPAction. But generally speaking I believe you're after placing your data in the XML, not in http headers.
Funny enough, I've downloaded the Java example from http://aws.amazon.com/code/Product-Advertising-API/2478 and if I read it correctly they're passing the signature in the URL (endpoint), not in the XML. Probably because it's a REST GET method (if you can access that API it could save you a lot of hair pulled, SOAP is clunky).

Resteasy, Make a Http-Put or Http-Post with Server-side Mock Framework of RestEasy

I wrote a Rest-Service which i would like to test.
I wanna run a JUnit test without having my server run. For this I am using the Server-side Mock Framework of RestEasy.
My question is, how can I make a Http-Put or Http-Post request with this framework with an marshalled Java Object in the Http-Body???
The Code below runs fine for an Http-Get, but how to make a Put or Post, maybe someone got some example code for this???
#Test
public void testClient() throws Exception {
Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
POJOResourceFactory noDefaults = new POJOResourceFactory(
MyClass.class);
dispatcher.getRegistry().addResourceFactory(noDefaults);
{
MockHttpRequest request = MockHttpRequest.get("/message/test/"
+ requestParam);
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
}
}
A bit late response but , might have some use for someone.
This is how i usually test my PUT requests. Hope it helps
#Test
public void testPUT() throws Exception {
POJOResourceFactory noDefaults = new POJOResourceFactory(REST.class);
Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
dispatcher.getRegistry().addResourceFactory(noDefaults);
String url = "your_url_here";
MockHttpRequest request = MockHttpRequest.put(url);
request.accept(MediaType.APPLICATION_JSON);
request.contentType(MediaType.APPLICATION_JSON_TYPE);
// res being your resource object
request.content(res.toJSONString().getBytes());
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
Assert.assertEquals( HttpStatus.SC_CREATED,response.getStatus());
}