I am very new to ASP.NET CORE MVC and I was wondering if anyone could help me about my problem.
I was working in a project that will get all projects within a specific azure devops organization.
Here is my controller code:
public async Task<ActionResult> Organization(string selectedOrg, string oauth)
{
var client = new HttpClient();
IndexViewModel model = new IndexViewModel();
model.Organizations = OrganizationData.Data;
if (selectedOrg == null)
{
selectedOrg = model.Organizations.FirstOrDefault().OrgName;
}
else
{
model.SelectedOrg = selectedOrg;
}
var token = _cache.Get<TokenModel>("Token" + HttpContext.Session.GetString("TokenGuid"));
oauth = token.AccessToken;
var url = "https://dev.azure.com/" + selectedOrg + "/_apis/projects?api-version=4.1";
try
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", oauth);
var response = await client.GetAsync(url);
var responseBody = response.Content.ReadAsStringAsync().Result;
model.Projects = JsonConvert.DeserializeObject<ProjectsModel>(responseBody);
client.Dispose();
return View("Index", model);
}
catch(Exception e)
{
client.Dispose();
return Json(Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(e.ToString()));
}
}
Can anyone help how to do unit testing with this one? Or do I have to refactor this one?
You have way to many dependencies.
Why does the signature of the method pass an oauth value that is never used?
First off, calling any external dependency via http inside a controller should be frowned upon. This whole thing should be abstracted into it's own call. Since it appears to be getting data, this should actually be at your data tier. Covering a whole n-tier approach with separate projects is most likely out of scope, so lets just cover the bare minimum for unit testing in my opinion.
First you need to abstract your HttpClient. You can't really do unit test methods if they make any calls outside themselves (for the most part) because then it's not a unit test, it's an integration test.
// I don't have a full grasp of your complete eco-system so based on the
// minimal information provided, this would at least get you close
public interface IAzureAPI
{
public Task<string> GetOrgAsync(string org, string oauth);
}
public class AzureAPI : IDisposable
{
public async Task<string> GetOrgAsync(string org, string oauth)
{
// use *using* not try/catch/finally/dispose
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", oauth);
var url = "https://dev.azure.com/" + org+ "/_apis/projects?api-version=4.1";
var response = await client.GetAsync(url);
// never use `.Result` unless you absolutely know what you are doing
// always using async/wait if possible
var result = await response.Content.ReadAsStringAsync();
return result;
}
}
}
Hopefully you are using a DI Framework:
public class MyController
{
private IAzureAPI _azureAPI;
public MyController(IAzureAPI azureAPI)
{
_azureAPI = azureAPI;
}
}
Now onto the hard part:
public async Task<ActionResult> Organization(string selectedOrg, string oauth)
{
IndexViewModel model = new IndexViewModel();
// I have no idea where model came from so
// this appears to block "unit-testing"
// strange that you don't validate `selectedOrg`, you just use it
model.Organizations = OrganizationData.Data;
if (selectedOrg == null)
{
selectedOrg = model.Organizations.FirstOrDefault().OrgName;
}
else
{
model.SelectedOrg = selectedOrg;
}
// no idea where `_cache` came from so
// also appears to block "unit-testing"
// As does `HttpContext` because you aren't using the
// Interface
var token = _cache.Get<TokenModel>("Token" + HttpContext.Session.GetString("TokenGuid"));
oauth = token.AccessToken;
try
{
var orgInfo = await _azureAPI.GetOrgAsync(selectedOrg, oauth);
model.Projects = JsonConvert.DeserializeObject<ProjectsModel>(orgInfo);
// return a view here???
return View("Index", model);
}
catch(Exception e)
{
// return JSON here instead????
return Json(Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(e.ToString()));
}
}
That's a general start, but there are too many unknowns, and to many dependencies to actually write a real unit test. Here is a quick structure and semi-test based on the information you've provided.
public MyControllerTests
{
// for 100% Cover Coverage you'd need all of these
public async Task Organization_OrgAsString_ReturnsView
{
//...
}
public async Task Organization_OrgAsNull_ReturnsView
{
// Arrange
var azureAPI = Substitute.For<IAzureAPI>();
azureAPI.GetOrgAsync(null, null)
.Returns("somestring");
var controller = new MyController(azureAPI);
// Act
var result = await controller.Organization(null, null);
// Assert
Assert.That(result....);
}
public async Task Organization_WithException_ReturnsJson
{
//...
}
}
Related
I'm trying to call an Api. If the call fails, I'm retrying with in the configured time out. When I'm writing the unit test for the scenario where the api repeated calls fails and the time out happens. I'm unable to determine what to Assert here. I think it's obvious to verify that the mockedBaseApiClient has never returned the response success for any of it's call in the execution. But I can't figure out how to verify the return type on the mocked object.
public async Task UpdateDocumentPath(UpdateDocument doc)
{
var path = $"v1/documents/{doc.accountId}/{doc.documentId}/paths";
try
{
var response = await _baseApiClient.PutAsync(DocumentsApiKey, path, doc);
if (response.IsSuccessStatusCode)
{
var updatedDocument = await response.Deserialize<UpdateDocument>();
var updatedPath = updatedDocument.documentPath;
}
else
{
await TryToReConnect(doc);
}
}
catch (Exception ex)
{
_exceptionPublisher.PublishException(ex);
await TryToReConnect(doc);
}
}
My Unit Test:
[Fact]
public async Task DocumentPatchAdapter_PatchDocument_RetriesWhenUnSuccessfullStatusCode_ButTimeoutExhausts_Tests()
{
MockConfiguration();
_mockedConfigurationSection.SetupGet(c => c.Value).Returns("20000");
HttpResponseMessage notFoundResponse = new HttpResponseMessage
{
StatusCode = HttpStatusCode.NotFound
};
_mockedBaseApiClient
.SetupSequence(c => c.PutAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<Object>()))
.ReturnsAsync(notFoundResponse)
.ReturnsAsync(notFoundResponse)
.ReturnsAsync(notFoundResponse);
UpdateDocument documentPathToBeUpdated = new UpdateDocument
{
accountId = 34512274,
documentPath = "\\\\sharoi.vliproj.com\\DevL\\DocumentMaker\\Print\\InsuranceScoreRenew_19196100600.pdf",
documentId = 3656261
};
await _documentPatchAdapter.UpdateDocumentPath(documentPathToBeUpdated);
//_mockedBaseApiClient.Verify(c=>c.PutAsync(.....)).NeverReturns(SuccessCode); I want something like this here
}
This is an example of an Action method inside HomeController:
[HttpPost]
public async Task<dynamic> UnitTest(string data)
{
var httpClient = new HttpClient();
var request = JsonConvert.SerializeObject(data);
var url = "https://jsonplaceholder.typicode.com/posts";
var response = await httpClient.PostAsync(url, new StringContent(request, Encoding.UTF8, "application/json"));
string responseContent = await response.Content.ReadAsStringAsync();
return responseContent;
}
I want to test it, but I do not know how. I tried the following:
[TestMethod]
public async Task JsonRightTest()
{
MyModelR model1 = new MyModelR
{
Title = "foo",
Body = "bar",
UserId = 1
};
string output1 = JsonConvert.SerializeObject(model1);
var url = "Home/UnitTest";
var response = await _client.PostAsync(url, new StringContent(output1, Encoding.UTF8, "application/json"));
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
var responseModel = JsonConvert.DeserializeObject<MyModel>(responseContent);
// Assert
Assert.AreEqual(1,
responseModel.UserId);
}
internal class MyModel
{
public string Title { get; set; }
public string Body { get; set; }
public int UserId { get; set; }
public int Id { get; set; }
}
internal class MyModelR
{
public string Title { get; set; }
public string Body { get; set; }
public int UserId { get; set; }
}
Unfortunately, the above does not work. Since I am very confused could you give me some answers to the following:
What's the best way to test UnitTest action? Is my approach wrong? Do I just have to call the API from JsonRightTest method and not involve the action?
Actually, in that case do we have a unit or integrated test?
I want to call the actual external end point.
The API (https://jsonplaceholder.typicode.com/posts) is found on the Internet and is available for testing purposes.
This appears to be an XY problem and a mixing of concerns.
The code under test is tightly coupled to implementation concerns and should encapsulate that external call behind a service abstraction that can be mocked during isolated unit tests.
Some refactoring steps that should be followed....
Those models being constructed in the test should be in the action.
[HttpPost]
public async Task<IActionResult> UnitTest([FromBody]MyDataR data) {
var httpClient = new HttpClient();
var requestJson = JsonConvert.SerializeObject(data);
var url = "https://jsonplaceholder.typicode.com/posts";
var response = await httpClient.PostAsync(url, new StringContent(requestJson, Encoding.UTF8, "application/json"));
if(response.IsSuccessStatusCode) {
var responseContent = await response.Content.ReadAsStringAsync();
var responseModel = JsonConvert.DeserializeObject<MyModel>(responseContent);
return Ok(responseModel);
}else
return StatusCode(response.StatusCode);
}
Refactoring further, the actual calling of the external endpoint should be abstracted away
public interface IExternalService {
Task<MyModel> PostDataAsync(MyData data);
}
and implemented accordingly
public class ExternalService : IExternalService {
// should consider abstracting this as well but that is another matter
static Lazy<HttpClient> _httpClient = new Lazy<HttpClient>(() => new HttpClient());
private HttpClient httpClient {
get { return _httpClient.Value; }
}
public async Task<MyModel> PostDataAsync(MyData data) {
var requestJson = JsonConvert.SerializeObject(data);
var url = "https://jsonplaceholder.typicode.com/posts";
var content = new StringContent(requestJson, Encoding.UTF8, "application/json")
var response = await httpClient.PostAsync(url, content);
var responseContent = await response.Content.ReadAsStringAsync();
if(response.IsSuccessStatusCode) {
var responseContent = await response.Content.ReadAsStringAsync();
var responseModel = JsonConvert.DeserializeObject<MyModel>(responseContent);
return responseModel;
}else
return null;
}
}
with the action in the the controller now looking like
private readonly IExternalService externalService; // Assumed injected into the controller
[HttpPost]
public async Task<IActionResult> UnitTest([FromBody]MyDataR data) {
var responseModel = await externalService.PostDataAsync(data);
if(responseModel != null) {
return Ok(responseModel);
}else
return BadRequest();
}
By removing the tight coupling to the external service call , this would allow the controller to be tested in isolation as needed to verify that it behaves as expected.
The external service call implementation can now be tested on its own if the desire is to check that the external end point behaves as expected. This would be considered an integration test due to its reliance on the actual external endpoint.
[TestMethod]
public async Task JsonRightTest() {
// Arrange
var expected = 1;
var model = new MyModelR {
Title = "foo",
Body = "bar",
UserId = 1
};
var target = new ExternalService(); // System under test
// Act
var responseModel = await target.PostDataAsync(model);
// Assert
Assert.IsNotNull(responseModel);
var actual = responseModel.UserId;
Assert.AreEqual(expected, actual);
}
This should now allow for easier inspection of the external service to verify that it behaves as expected.
In production you would make sure that the external service abstraction and its implementation are registered in the composition root.
services.AddTransient<IExternalService, ExternalService>();
so that it is injected into the dependent controller correctly.
I am trying to write a function which uses Task and TaskCompletion.
My problem is that after login, the result is not returned. I used similar code before and it was working. I do not know what causes for this situation.
public async Task<byte[]> Sign(byte[] documentContent)
{
var service = new SignServiceWrapper("https://example.com?wsdl");
var loginResult = await Task.Run(() => service.Login(loginRequest));
//....
}
and my SignServiceWrapper class
public class SignServiceWrapper
{
private static string _webServiceUrl;
private BrokerClientClient client;
public SignServiceWrapper(string webServiceUrl)
{
_webServiceUrl = webServiceUrl;
}
public Task<loginResponse> Login(loginRequest request)
{
var tcs = new TaskCompletionSource<loginResponse>();
ClientGenerator.WebServiceUrl = _webServiceUrl;
ClientGenerator.InitializeService();
client = ClientGenerator.ServiceClient;
client.loginCompleted += (sender, loginResult) =>
{
if (loginResult.Error != null)
tcs.SetException(loginResult.Error);
else
tcs.TrySetResult(loginResult.Result);
};
client.loginAsync(request);
return tcs.Task;
}
// ...
}
If I call my login function like that it works
var loginResult = Task.Run(() => service.Login(loginRequest));
loginResult.Wait();
I know that there is kind of a deadlock but I don't know how to solve this here and which object.
Here is a working .NET Fiddle.
I think your .Login method is trying to do too much. The first thing that I noticed (and can only imagine how it's implemented) is the static ClientGenerator, that has static mutable state. This which is alarming and a very specific code smell. I would love to see what the client itself looks like and how that is implemented as that would certainly help to better answer this question.
Based on what you shared thus far (and assuming that the client.loginAsync returns a Task<loginResponse>), I would say that you could do the following:
public class SignServiceWrapper
{
private static string _webServiceUrl;
private BrokerClientClient client;
public SignServiceWrapper(string webServiceUrl)
{
_webServiceUrl = webServiceUrl;
}
public Task<loginResponse> LoginAsync(loginRequest request)
{
ClientGenerator.WebServiceUrl = _webServiceUrl;
ClientGenerator.InitializeService();
client = ClientGenerator.ServiceClient;
return client.loginAsync(request);
}
// ...
}
You could then consume this as such:
public async Task<byte[]> Sign(byte[] documentContent)
{
var service = new SignServiceWrapper("https://example.com?wsdl");
var loginResult = await service.LoginAsync(loginRequest);
//...
}
If the client.loginAsync doesn't return what you're looking for, then you'll need to approach this doing something similar to your current approach. Or if you are locked in to the event-based async pattern, you have other considerations - like whether or not you want to support cancellation, IsBusy, progress, incremental results and if you have the ability to have the event args inherit the System.ComponentModel.AsyncCompletedEventArgs, etc...
One final consideration, if the client.loginAsync is Task returning, even if it doesn't return the loginResponse you need to await it like so:
public async Task<loginResponse> Login(loginRequest request)
{
var tcs = new TaskCompletionSource<loginResponse>();
ClientGenerator.WebServiceUrl = _webServiceUrl;
ClientGenerator.InitializeService();
client = ClientGenerator.ServiceClient;
client.loginCompleted += (sender, loginResult) =>
{
if (loginResult.Error != null)
tcs.SetException(loginResult.Error);
else
tcs.TrySetResult(loginResult.Result);
};
await client.loginAsync(request);
return tcs.Task;
}
Update
After discussion with OP this .NET Fiddle seemed to align with his needs.
Change var loginResult = await Task.Run(() =>service.Login(loginRequest));
To var loginResult = await service.Login(loginRequest);
I'm working on a project that retrieves information from an external webservice API, but I'm not sure how I'm supposed to test it, I'm quite new at Testing and I have done just a couple of Unit Test, but as far as I know I have to mock the webservice functionality, I've been looking for info regarding this subject but haven't found anything for Windows Phone yet. What's the standard procedure for these type of cases?
Here's a simple version of what I want to test:
public async Task<List<Song>> FetchSongsAsync(String query)
{
if (String.IsNullOrEmpty(query))
return null;
string requestUrl = "webservice url";
var client = new HttpClient();
var result = await client.GetStringAsync(new Uri(requestUrl,UriKind.Absolute));
try
{
var result = JsonConvert.DeserializeObject<RootObject>(result);
return result;
}
catch (Exception)
{
return null;
}
}
Thanks!
Decouple your code from its dependencies: make content loading and its deserialization replaceable:
private readonly IClient client;
private readonly ISerializer serializer;
public YourService(IClient client, ISerializer serializer)
{
_client = client;
_serializer = serializer;
}
public async Task<List<Song>> FetchSongsAsync(String query)
{
try
{
var result = await _client.GetStringAsync(new Uri("http://example.com"));
return _serializer.DeserializeObject<RootObject>(result);
}
catch (Exception)
{
return null;
}
}
The first thing that may help is understand and use dependency injection. Basically taking any dependencies of your object/method/etc and (as it states) injecting them into the object/method/etc. For example, you are having a difficult time figuring out how to test the method because the method depends on being able to access the web service. There are a couple things you can do after this.
One thing to do is to check out mocking frameworks such as Moq.
Another thing I recently did was I added an overloaded constructor (dependency injection) that takes a HttpMessageInvoker object (note HttpClient derives from this). This way I could instantiate the class with my own response message:
public class MyLoader()
{
protected HttpMessageInvoker MessageInvoker { get; set; }
private HttpRequestMessage requestMessage;
public MyLoader() // default constructor
{
MessageInvoker = new HttpClient();
}
public MyLoader(HttpMessageInvoker httpMessageInvoker)
{
MessageInvoker = httpMessageInvoker;
}
public object DoSomething()
{
var response = await MessageInvoker.SendAsync(requestMessage, cancellationTokenSource.Token);
}
Here is my mock message invoker:
public class MockMessageInvoker : HttpMessageInvoker
{
public string ResponseString { get; set; }
public MockMessageInvoker(string responseString)
: base(new HttpClientHandler())
{
ResponseString = responseString;
}
public override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
return Task.Run<HttpResponseMessage>(() =>
{
HttpResponseMessage responseMessage = new HttpResponseMessage(
System.Net.HttpStatusCode.OK);
var bytes = Encoding.ASCII.GetBytes(ResponseString);
var stream = new System.IO.MemoryStream(bytes);
responseMessage.Content = new StreamContent(stream);
return responseMessage;
});
}
}
I can call it all like so:
MyLoader loader = new MyLoader(new MockMessageInvoker(validJsonResponse));
loader.DoSomething() // I've removed the dependency on the service and have control of the content in the response
It's quick and dirty, but does the trick.
Hope this helps.
I'm wondering how to consume a WEBAPI from another ASP.Net Web API to store the response in a database.
I know how to consume a WEBAPI from clients like javascript,console application etc.
But the requirement is to pull the data from third party API by my WEBAPI & store the result in a database so that using my WEBAPI my clients request me for data.
Is it possible to do this with an Asp.Net Web API?
In this tutorial is explained how to consume a web api with C#, in this example a console application is used, but you can also use another web api to consume of course.
http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client
You should have a look at the HttpClient
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost/yourwebapi");
Make sure your requests ask for the response in JSON using the Accept header like this:
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
Now comes the part that differs from the tutorial, make sure you have the same objects as the other WEB API, if not, then you have to map the objects to your own objects. ASP.NET will convert the JSON you receive to the object you want it to be.
HttpResponseMessage response = client.GetAsync("api/yourcustomobjects").Result;
if (response.IsSuccessStatusCode)
{
var yourcustomobjects = response.Content.ReadAsAsync<IEnumerable<YourCustomObject>>().Result;
foreach (var x in yourcustomobjects)
{
//Call your store method and pass in your own object
SaveCustomObjectToDB(x);
}
}
else
{
//Something has gone wrong, handle it here
}
please note that I use .Result for the case of the example. You should consider using the async await pattern here.
For some unexplained reason this solution doesn't work for me (maybe some incompatibility of types), so I came up with a solution for myself:
HttpResponseMessage response = await client.GetAsync("api/yourcustomobjects");
if (response.IsSuccessStatusCode)
{
var data = await response.Content.ReadAsStringAsync();
var product = JsonConvert.DeserializeObject<Product>(data);
}
This way my content is parsed into a JSON string and then I convert it to my object.
public class EmployeeApiController : ApiController
{
private readonly IEmployee _employeeRepositary;
public EmployeeApiController()
{
_employeeRepositary = new EmployeeRepositary();
}
public async Task<HttpResponseMessage> Create(EmployeeModel Employee)
{
var returnStatus = await _employeeRepositary.Create(Employee);
return Request.CreateResponse(HttpStatusCode.OK, returnStatus);
}
}
Persistance
public async Task<ResponseStatusViewModel> Create(EmployeeModel Employee)
{
var responseStatusViewModel = new ResponseStatusViewModel();
var connection = new SqlConnection(EmployeeConfig.EmployeeConnectionString);
var command = new SqlCommand("usp_CreateEmployee", connection);
command.CommandType = CommandType.StoredProcedure;
var pEmployeeName = new SqlParameter("#EmployeeName", SqlDbType.VarChar, 50);
pEmployeeName.Value = Employee.EmployeeName;
command.Parameters.Add(pEmployeeName);
try
{
await connection.OpenAsync();
await command.ExecuteNonQueryAsync();
command.Dispose();
connection.Dispose();
}
catch (Exception ex)
{
throw ex;
}
return responseStatusViewModel;
}
Repository
Task<ResponseStatusViewModel> Create(EmployeeModel Employee);
public class EmployeeConfig
{
public static string EmployeeConnectionString;
private const string EmployeeConnectionStringKey = "EmployeeConnectionString";
public static void InitializeConfig()
{
EmployeeConnectionString = GetConnectionStringValue(EmployeeConnectionStringKey);
}
private static string GetConnectionStringValue(string connectionStringName)
{
return Convert.ToString(ConfigurationManager.ConnectionStrings[connectionStringName]);
}
}