I want to test method using async method.
But, when i run test, UnityEditor is blocking.
I think, this problem is because async method.
i don't know how to solve this problem.
Unity version : Unity 2020.3.33f1
public async static Task<string> GetAsync() {
// Do something
HttpResponseMessage response = await request.GetAsync(..);
string responseData = await response.Content.ReadAsStringAsync();
return response Data
}
...
public string GetData() {
Task<string> res = GetAsync();
return res.Result;
}
////////////////// Test Code //////////////
[Test]
public void Test_GetData() {
...
string res = GetData()
...
}
Without testing it, you need to use async/await in all places.
When using async/await, as you have done Task for returning string type, but for void method, you just use Task.
let's say
public static async Task<string> GetAsync()
{
return await Task.FromResult("test");
}
and your test should be like this:
[Test]
public async Task Test_GetAsync()
{
var result = await GetAsync();
Assert.AreEqual("test", result);
}
if we take your code so
public async static Task<string> GetAsync() {
// what ever
.....
return responseData
}
the test will be:
[Test]
public async Task Test_GetData() {
...
string res = await GetData()
...
}
If your test project is an older .net framework, you would level it up to a newer version as this answer suggests. Otherwise, if you are locked and not able to upgrade, you can do something which I am not suggesting as this answer mentions.
[Test]
public void Test_GetData()
{
var result = GetAsync().GetAwaiter();
Assert.AreEqual("test", result.GetResult());
}
Related
I am setting up a new server, and I want to expose Async API, this API will call a function and this function will call another function and so on, the last function in the calling tree will call an external service and use Async/Await code pattern. what is the right way to implement such API?
Shall I add Async/Await in all functions or just adding them in the last function?
E.g.
[ResponseType(typeof(AnyTypeResponse))]
[HttpPost]
public async Task<IHttpActionResult> MyAPI()
{
var res = await MyFuncTree1();
return Ok(res);
}
public async Task<AnyTypeResponse> MyFuncTree1()
{
var res = await MyFuncTree2();
return res;
}
public async Task<AnyTypeResponse> MyFuncTree2()
{
var res = await MyFuncTree3();
return res;
}
public async Task<AnyTypeResponse> MyFuncTree3()
{
var res = await CallExternalService();
return res;
}
Only the top function needs to be marked async in your example and await the result of MyFuncTree1. The others can just return the result task of the function they are calling (as the result is not used inside the function).
[ResponseType(typeof(AnyTypeResponse))]
[HttpPost]
public async Task<IHttpActionResult> MyAPI()
{
var res = await MyFuncTree1();
return Ok(res);
}
public Task<AnyTypeResponse> MyFuncTree1()
{
return MyFuncTree2();
}
public Task<AnyTypeResponse> MyFuncTree2()
{
return MyFuncTree3();
}
public Task<AnyTypeResponse> MyFuncTree3()
{
return CallExternalService();
}
I have an async Task unit test (MVC, c#, .NET 4.5.2). It does an await on a aysnc Task<ActionResult> method, which in turn has an await call on a async method.
The test, and others like it, will pass if I select them and choose Debug Selected Tests from the right-click menu in Visual Studio 2017.
The problem is when I select Run Selected Tests or Run All. It is then that many of the tests will fail if they follow the condition mentioned at the beginning. Any test that only returns a RedirectToRouteResult without having gone the aforementioned drill-down will pass.
[TestMethod]
public async Task TestPartsController_GetPartInfo_ReturnsInfo()
{
//arrange
PartController pc = new PartController();
//act
var result = await pc.GetPartInfo("PC123456");
//assert
Assert.IsIntanceOfType(result, typeof(ViewResult));
Assert.AreEqual("Form", ((ViewResult)result).ViewName);
Assert.AreEqual("PC123456", result.Model.PartNum.ToUpper());
}
public async Task<ActionResult> GetPartInfo(string partNum)
{
if (string.IsNullOrEmpty(partNum)
{
return RedirectToAction("Index")
}
var response = await ServiceClient.GetJsonAsync("/part/partinfo", "?partNum=" + partNum;
response.EnsureSuccessStatusCode();
results = await response.Content.ReadAsAsync<Dto.PartNumInfo>();
...
return View("Form", model);
}
public async Task<HttpResponseMessage> GetAsync(Controllers controller, string criteria)
{
HttpClient client;
string service = GetService(controller, out client);
var response = await client.GetAsync(service + criteria);
return response;
}
Solution
Use async/await all the way through as well as using statements and IDisposable.
public async Task<HttpResponseMessage> GetJsonAsync<T>(Controllers controller, T data)
{
HttpResponseMessage response;
using (var service = new MyService())
{
HttpClient http;
string serviceLoc = service.GetServiceClient(controller, out http);
response = await http.GetAsync(serviceLoc, data);
}
return response;
}
Solution Use async/await all the way through as well as using statements and IDisposable.
public async Task<HttpResponseMessage> GetJsonAsync<T>(Controllers controller, T data)
{
HttpResponseMessage response;
using (var service = new MyService())
{
HttpClient http;
string serviceLoc = service.GetServiceClient(controller, out http);
response = await http.GetAsync(serviceLoc, data);
}
return response;
}
I have the following class and the interface
public interface IService
{
Task<double> GetAccDetails(int personId);
}
public class Person
{
private int _personId;
private IService _service;
public Person(int personId, IService service)
{
_personId= personId;
_service = service;
}
public double Amount {get; set;}
public async void UpdateBanckingAcc()
{
Amount = await _service.GetAccDetails(_personId);
}
}
I am trying to write nunit test for it:
[Test]
public async void Test1([Values(200)]int personId)
{
const double expectedResult = 20;
var serviceMock = new Mock<IAccountService>();
//Here I tried both options:
//serviceMock.Setup(s => s.GetAccDetails(It.Is<int>(id => id == personId)))
// .ReturnsAsync(() => expectedResult);
//And:
serviceMock.Setup(s=> s.GetAccDetails(It.Is<int>(id => id == personId)))
.Returns(() => Task.FromResult<double>(personId));
var person = new Person(personId, serviceMock.Object);
person.UpdateBanckingAcc();
double res = person.Amount;
Assert.AreEqual(expectedResult, res);
}
And the test fails. For some strange reason I can not debug it.
So the issue I see here is the call :
person.UpdateBanckingAcc();
it should be
await person.UpdateBanckingAcc();
but it does not like if I use await keyword.
Please advise.
Also one more question: is there something specific in terms of nunit testing for async methods I should test, like task status testing, etc?
The problem here is that your method UpdateBankingAcc has return type void which should be returning a Task<T> or Task, so you need to change the signatures of it to reutrn a Task like:
public async Task UpdateBanckingAcc()
{
Amount = await _service.GetAccDetails(_personId);
}
and now you would need to change your test code to be:
await person.UpdateBanckingAcc();
double res = person.Amount;
Assert.AreEqual(expectedResult, res);
you should never return void from an async method, unless it is UI controls events, you can read about the best practices of using async and await at following :
https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
http://www.tonicodes.net/blog/why-you-should-almost-never-write-void-asynchronous-methods/
async/await - when to return a Task vs void?
There is a simple rule: async void is used for fire-and-forget behavior and only for this. If you need async method, change it's return type to the Task, as #EhsanSajjad said. This corresponds to the unit tests too:
public async Task UpdateBanckingAcc()
public async Task Test1([Values(200)]int personId)
I have an issue with a task blocking when I try to retrieve it's result.
I have the following piece of code I want executed synchronously (which is why I'm looking for the result)
I would ignore the reason each call has to be made (legacy software that requires multiple calls through different layers)
the call seems to break down after it starts the task for the final call to be made in the PostCreateProfile, I can see this request never makes it any further than this.
if (CreateProfile(demographics).Result) // Task blocks here
{
//dothing
}
private async Task<bool> CreateProfile(Demographics demographics)
{
ProfileService profileService = new ProfileService();
CreateProfileBindingModel createProfileBindingModel = this.CreateProfileModel(demographics);
return await profileService.Create(createProfileBindingModel);
}
public async Task<bool> Create(CreateProfileBindingModel model)
{
HttpResponseMessage response = await profileServiceRequest.PostCreateProfile(rootURL, model);
return response.IsSuccessStatusCode;
}
public Task<HttpResponseMessage> PostCreateProfile(string url, CreateProfileBindingModel model)
{
HttpContent contents = SerialiseModelData(model);
var resultTask = client.PostAsync(url, contents);
return resultTask;
}
The request will reach its destination if I was to change CreateProfile to an async void like so:
private async void CreateProfile(AppointmentController controller)
{
ProfileService profileService = new ProfileService();
CreateProfileBindingModel createProfileBindingModel = this.CreateProfileModel(controller);
await profileService.Create(createProfileBindingModel);
}
But I can't return the bool I want to use from this.
Can anyone point out what I am doing wrong?
You should never call .Result on a async/await chain.
Whatever code that calls CreateProfile(demographics) needs to be async too so it can do
if (await CreateProfile(demographics))
{
//dothing
}
Also, if you can you really should put .ConfigureAwait(false) wherever it is logically possible.
if (await CreateProfile(demographics).ConfigureAwait(false)) // depending on what dothing is you may not want it here.
{
//dothing
}
private async Task<bool> CreateProfile(Demographics demographics)
{
ProfileService profileService = new ProfileService();
CreateProfileBindingModel createProfileBindingModel = this.CreateProfileModel(demographics);
return await profileService.Create(createProfileBindingModel).ConfigureAwait(false);
}
public async Task<bool> Create(CreateProfileBindingModel model)
{
HttpResponseMessage response = await profileServiceRequest.PostCreateProfile(rootURL, model).ConfigureAwait(false);
return response.IsSuccessStatusCode;
}
public Task<HttpResponseMessage> PostCreateProfile(string url, CreateProfileBindingModel model)
{
HttpContent contents = SerialiseModelData(model);
var resultTask = client.PostAsync(url, contents);
return resultTask;
}
I often write code that has convenience methods which basically wrap other methods. Here's a simple example:
public class WithoutAsync
{
public static ReadOnlyCollection<Response> GetResponses(IEnumerable<Request> fromRequests)
{
var ret = new List<Response>();
foreach (Request r in fromRequests)
{
ret.Add(new Response());
}
return ret.AsReadOnly();
}
//convenience method
public static Response GetResponse(Request fromRequest)
{
return GetResponses(new Request[] {fromRequest})[0];
}
}
Now I want to await long-running operations but I can't quite figure out how to retrofit this methodology for use with TPL:
public class WithAsync
{
public static async Task<ReadOnlyCollection<Response>> GetResponses(IEnumerable<Request> fromRequests)
{
var awaitableResponses = new List<Task<Response>>();
foreach (Request r in fromRequests)
{
awaitableResponses.Add(Task.Run<Response>(async () =>
{
await Task.Delay(10000); //simulate some long running async op.
return new Response();
}));
}
return new List<Response>(await Task.WhenAll(awaitableResponses)).AsReadOnly();
}
//convenience method
public static Task<Response> GetResponse(Request fromRequest)
{
return GetResponse(new Request[] { fromRequest });
}
}
The convenience method above obviously won't work because it's trying to return a Task<ReadOnlyCollection<Response>> when it really needs to return a Task<Response>.
This works:
//convenience method
public static Task<Response> GetResponse(Request fromRequest)
{
return new Task<Response>(new Func<Response>(() => GetResponse(new Request[] { fromRequest }).Result[0]));
}
but it seems really awkward, and more importantly, it blocks on .Result[0] which is potentially on a UI thread.
Is there any good way to accomplish what I'm trying to do?
You're trying to avoid making that "convenience method" async, but there's no reason to do that.
What you want is to call the other method, wait until there are responses and then get the first and only one. You can do that by making it async and using await:
async Task<Response> GetResponseAsync(Request fromRequest)
{
var responses = await GetResponsesAsync(new[] { fromRequest });
return responses.Single();
}
Although a better solution in this specific case is to switch things around and have the single GetResponse actually do that work of a single request, and have the multiple GetRsponses call it instead:
async Task<ReadOnlyCollection<Response>> GetResponsesAsync(IEnumerable<Request> fromRequests)
{
return (await Task.WhenAll(fromRequests.Select(GetResponse))).ToList().AsReadOnly();
}
async Task<Response> GetResponseAsync(Request fromRequest)
{
await Task.Delay(10000); //simulate some long running async op.
return new Response();
}
Notes:
I know it's an example, but there's probably no reason to use Task.Run instead of a simple async call.
The convention is to name async methods with an "Async" suffix (i.e. GetResponseAsync).
I've also pluralized the name of the method that returns a collection.
I'm still sticking with I3arnon's answer because it's a well-written, informative answer, but I'd like to submit my own answer because I realized that I was almost there. Here's the async convenience method I was struggling to find:
//convenience method
public static async Task<Response> GetResponse(Request fromRequest)
{
return (await GetResponses(new Request[] { fromRequest }))[0];
}