I need to unit test a method which loads with data in async fashion.
I can easily run async tests methods via
[Test]
public async Task My_test_async() {
// ... await something
}
But I also want the Setup method to be async. Because it prepares some data in mocked Db. This mocked db is of course also async (it has to implement the same interface).
So my setup method looks like this:
[Setup]
public async Task Setup() {
var db = new InMemoryDbContext();
// ... add sample data in db context
// ... then save them
await db.SaveChangesAsync();
}
But this results in my tests being skipped by NUnit Runner
I am using NUnit version 3.0.1, NUnitTestAdapter.WithFramework version 2.0.0 and VisualStudio 2015 with Resharper 9.2
Possible workarounds
I can workaround this problem, but neither solution feels nice.
Workaround #1
Refactor Setup() method to be private, remove the [Setup] attribute from it, and call it in every test method. That way it can be awaited and tests will execute.
Workaround #2
Or I can make the Setup synchronous, and wrap the async code in Task.Run().Result, like this
var r = Task.Run(() => db.SaveChangesAsync()).Result;
But both workarounds are ugly.
Does anyone knows a better solution?
In NUnit3
[OneTimeSetUp]
public async Task OneTimeSetup()
{
// fixture one time setup code, can use await here
}
[SetUp]
public async Task Setup()
{
// per test setup, can use await here
}
Work around #2 :D
[SetUp]
public void Setup()
{
SetupAsync().Wait();
}
public async Task SetupAsync()
{
var db = new InMemoryDbContext();
// ... add sample data in db context
// ... then save them
await db.SaveChangesAsync();
}
Related
I have a TestMethod async task that is mocking a service setup with ReturnsAsync but for some reason the result keeps returning null.
[TestMethod]
public async Task GetCustomerAsync_Returns_CustomerResults()
{
var customerResults = _fixture.Create<CustomerResults>();
_mockCustomerService.Setup(s => s.GetCustomerAsync(1)).ReturnsAsync(customerResults);
var result = await _customerManager.GetCustomerDetails(1);
Asset.IsNotNull(result);
}
public async Task<CustomerResults> GetCustomerDetails(int id)
{
var results = await _customerService.GetCustomerAsync(id);
return results;
}
You should have posted all the code needed to understand the problem, the creation of _mockCustomerService and _fixture variable, etc.
Having said that i can probably make a guess that you are creating the mockerService and not 'Frezzing' it. The call to _customerManager is not using the _mockCustomerService that you want it to use. You can read about this here AutoFixture Freeze
I have a method called myMethodAsync, which needs to be executed, make some stuff and then run DoSomeWork method - however it doesn't need to wait until the method is done.
It's an asp.net core 2.0 application using Entity Framework Core and the built-in dependency injection. Every class in the sample is Scoped. I'm using repository pattern. There is no error, just nothing is happening If I set breakpoint after myRepository.GetAsync or in the GetAsync method the debugger doesn't get in.
The code:
public async Task myMethodAsync
{
...
await myRepository.AddAsync(entity);
DoSomeWork(id); // If it's lack of await the line below will not works
}
private async Task DoSomeWork(Guid id)
{
...
var someEntity = await myRepository.GetAsync(id); // This line will never be done
}
I thought that it's because the myRepository is shared somehow, so I extracted the DoSomeWork to other class with own myRepository, but the effect is the same.
Also If I use Task.Run nothing changes.
How do I know that the code is never executed? Beacuse I'm changing the entity and updating it to database later. However the entity is not changed.
Also really intersting is that this following code almost works:
public async Task myMethodAsync
{
...
await myRepository.AddAsync(entity);
DoSomeWork(id); // Now it almost works
await myRepository.GetAsync(randomID);
}
private async Task DoSomeWork(Guid id)
{
...
var someEntity = await myRepository.GetAsync(id); // It works now
...
await myRepository.UpdateAsync(entity); // But it doesn't work
}
I've found a solution. The problem was with EF - my DbContext was disposed(it didn't throw an exception cause of multi-threading I think). I needed to implement ICloneable interface to DbContext and myRepository. Now I'm passing cloned version of myRepository and everything works fine.
public async Task myMethodAsync
{
...
await myRepository.AddAsync(entity);
DoSomeWork(id, (Repository)myRepository.Clone());
}
private async Task DoSomeWork(Guid id, Repository clonedRepository)
{
...
var someEntity = await clonedRepository.GetAsync(id);
}
[TestMethod]
public void TestMethod1()
{
TestClass testClass = new TestClass();
testClass.Method();
Assert.AreEqual(testClass.x, true);
}
And test class:
public async void Method()
{
if(cond)
await InnerMethod();
}
private async Task InnerMethod()
{
var data = await client.FetchData();
x = data.res;
}
I am testing an sync method which is of this format. But when i run the test, it runs through the line
var data = await client.FetchData();
and then instead of continuing the method execution, goes into the assert statement in the test method first (fails because obviously it didnt finish the method). and THEN carries on with the rest of the method.
I am really confused why its doing this but am guessing its soemthing to do with threading. any clues as to why this behavior would be really helpful! thanks
Make your test method asynchronous as well public async Task TestMethod1() and await inside the test await testClass.Method();. I'm not sure about MSTest but it works OK with xUnit.
Also as written in the comment below you should use public async Task Method1(). Read Async/Await - Best Practices in Asynchronous Programming.
I have a unit test project using xUnit.net v.2.3.1 for my ASP.NET Core 2.0 web app.
My test should focus on testing a given DataEntry instance: DataEntry instances are generated by the async method GenerateData() in my DataService class, which looks like:
public class DataService {
...
public async Task<List<DataEntry>> GenerateData() {
...
}
...
}
I am writing this test case as a Theory so my test can focus on a DataEntry instance at a time. Here is the code:
[Theory]
[MemberData(nameof(GetDataEntries))]
public void Test_DataEntry(DataEntry entry) {
// my assertions
Assert.NotNull(entry);
...
}
public static async Task<IEnumerable<object[]>> GetDataEntries() {
var service = new DataService();
List<DataEntry> entries = await service.GenerateData().ConfigureAwait(false);
return entries.Select(e => new object[] { e });
}
However, I get the following error at compile time:
MemberData must reference a data type assignable to 'System.Collections.Generic.IEnumerable<object[]>'. The referenced type 'System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<object[]>>' is not valid.
From the error description, it seems xUnit.net does not allow MemberData to use an async static method, like my GetDataEntries() one. Is there any functionality gap in xUnit.net I should be aware of?
Now, I know I could switch my Theory into a Fact and loop through each DataEntry in the list returned by my DataService, however I would prefer to keep a Theory setup as my test would be cleaner and focused on DataEntry instead of List<DataEntry>.
Question: is there any way in xUnit.net to let my Theory get data from my DataService async API? Please, note the DataService class cannot be changed nor extended to provide data synchronously.
EDIT
I am looking for a way through async/await and would prefer to avoid any usage of blocking calls such as Task<T>.Result e.g. on my GenerateData() method, as the underlying thread will be blocked til the operation completes.
This is relevant in my test project as I have other similar test cases where data should be retrieved in the same way and therefore I want to avoid ending up with too many blocking calls, but instead keeping the async/await propagation.
Until xUnit allows async theory data, you can use Task<T> instances as theory data and await them inside the test method (note that test methods can be async):
public static IEnumerable<object> GetDataEntries() {
var service = new DataService();
yield return new object[] { service.GenerateData() };
}
[Theory]
[MemberData(nameof(GetDataEntries))]
public async Task Test_DataEntry(Task<List<DataEntry>> task) {
List<DataEntry> entries = await task;
for (int i = 0; i < entries.Count; i++) {
// my assertions
Assert.NotNull(entries[i]);
}
}
This functionality is not provided internally. You can try following:
Write your CustomMemberDataAttribute by inheriting DataAttribute.
Override 'GetData' method of parent class.
Make the method async, that, provides data.
Call async data provider method from 'GetData' method.
Use your CustomMemberDataAttribute to decorate test cases.
You can refer following link to write your custom attribute.
Keep other method same, just modify 'GetData' method as discuss above.
https://github.com/xunit/xunit/blob/bccfcccf26b2c63c90573fe1a17e6572882ef39c/src/xunit.core/MemberDataAttributeBase.cs
I want to convert this unit test into BDD using storyQ
working unit test
[Test]
public async void CreateNewProjectAndDatabase()
{
StartParametersAndAteEngineDlls();
await TheNewDatabaseAndProjectIsCreated();
TheDataBaseViewModelIsCreated();
TheMainViewModelIsCreated();
}
private async Task TheNewDatabaseAndProjectIsCreated()
{
....
}
converted to BDD
[Test]
public async Task CreateNewProjectAndDatabase()
{
_story.WithScenario("Create a new bla bla")
.Given(StartParametersAndAteEngineDlls)
.When(async ()=> await TheNewDatabaseAndProjectIsCreated())
.Then(TheDataBaseViewModelIsCreated)
.And(TheMainViewModelIsCreated)
.Execute();
}
the code is code is compiling however I get an ArgumentException
If you use 2 underscores in your method name, make sure there's 2 arguments (found 0)
I know I'm a bit late. I had the same problem I fixed it changing the way I execute the When method. Instead of using await and having a Task I used the oldSchool function "Wait" inside the When method. In that way we can have a private void function that StoryQ understand.
Something like this.
private void MyWhenMethod()
{
_sut.AsyncMethodRun().Wait()
}