xUnit not awaiting async test - c#

On VS 2013, I can't get this async test to fail.
I have xUnit 1.8.0.1539 (installed from nuget), with the xUnit Test Runner VS extension (0.99.5). All current, AFAIK.
I happen to also have Moq, AutoFixture, and FluentAssertions reference in the unit test, but I don't think that matters (but I'm admitting it in case it does).
I have done async unit tests in other areas of my solution, and they work.
I'm missing something with this newly created tests, and I can't tell what I'm missing or doing wrong.
NOTE The SUT code is not meant to be complete. I'm just trying to get the red light first, before I write the code to make the test go green.
Here's the test code:
using System.Threading.Tasks;
using FluentAssertions;
using Xunit;
namespace MobileApp.Proxy.Test
{
public class WhenRetrievingPriceDataFromClient
{
[Fact]
public async Task GroupReportIsReturnedWithSomeData()
{
// arrange
var sut = new Client();
// act
var actual = await sut.GetReportGroupAsync();
// assert
// Xunit test
Assert.Null(actual);
Assert.NotNull(actual);
// FluentAssertions
actual.Should().BeNull();
actual.Should().NotBeNull();
}
}
}
And here is the SUT code:
using System;
using System.Diagnostics;
using System.Net.Http;
using System.Threading.Tasks;
using MobileApp.Proxy.Properties;
namespace MobileApp.Proxy
{
public class Client
{
public async Task<ReportGroup> GetReportGroupAsync()
{
return await Task.FromResult(new ReportGroup());
}
}
}
Obviously, this test should fail! The Asserts for Null and NotNull can't both succeed, so my conclusion is that the test is exiting before it finishes getting the response from the SUT.
What did I miss?
OR, is there a better way I should have started an async test to make sure it fails before writing the SUT code?

You need xUnit 1.9 for async unit tests to work correctly.

Async tests are supported in xUnit v1.9 or later. If you're stuck with an earlier version, you'll need to do something like this:
[Fact]
public void GroupReportIsReturnedWithSomeData()
{
GroupReportIsReturnedWithSomeDataAsync().Wait();
}
private async Task GroupReportIsReturnedWithSomeDataAsync()
{
// arrange
var sut = new Client();
// act
var actual = await sut.GetReportGroupAsync();
// assert
// Xunit test
Assert.Null(actual);
Assert.NotNull(actual);
// FluentAssertions
actual.Should().BeNull();
actual.Should().NotBeNull();
}
Basically, the test method blocks until the async test method completes, whether it'd due to successful completion or fault (e.g., a failed assertion). In the case of a fault, the exceptions will propagate to the main test thread through Wait().
You may want to pass a timeout to Wait() so your test will fail if it hasn't completed after a certain amount of time. As written, the test could block indefinitely if the async method never completes.

Related

How to pass data from one test to another in Xunit?

I am using Playwright with C# and Xunit, but I think Selenium and Xunit users can help as well.
I need to get the value of an element in one test and pass this value to another test.
For example,
[Fact]
public async Task GetData()
{
var data = await Page.GetAttribute(selector1, "value");
}
[Fact]
public async Task PassData()
{
await Page.FillAsync(selector2, data);
}
This is a simple example, the real-life test has a lot of steps, so I want to break one big into several small tests.

How do I verify if something didn't happen?

We are using OpenCover for our solution test coverage and I noticed that
public async Task Build(ProcessorContext context)
{
context.ResultBetSlip.Bets.Clear();
// Here OpenCover tells me that I need to cover two branches
// so I assume I need to verify that GetAvailablePlugins can be empty and
// no Build method was called.
// How do I do that?
foreach (var plugin in _pluginFactory.GetAvailablePlugins())
{
await plugin.Build(context);
}
}
Now my test would look like that
[Test]
public async Task Build_ShouldntEnterForeachWhenThereAreNoPluginsRegistered()
{
// Arrange
var pluginFactoryMock = new Mock<IBetSlipProcessorServicePluginFactory>();
var sut = new BetSlipProcessorService(pluginFactoryMock.Object);
pluginFactoryMock
.Setup(pf => pf.GetAvailablePlugins())
.Returns(new List<IBetSlipProcessorServicePlugin>());
// Act
await sut.Build(AutoFixtureSimplified.Create<ProcessorContext>());
// Assert
???
}
Should I even consider testing such case if it is possible?
EDIT:
As requested this is the test coverage report:
And here you can find gist of all the tests that I do in order to achieve such coverage.
https://gist.github.com/kuskmen/df3f112b2b6d880741ee6ab559d64d53
I am assuming you are using the Moq framework for mocking. If this is the case you can do one of two things.
You can create your mock in strict mode
You can expect that when the plugin.Build(..) method is called that an exception is thrown.
A similar question was asked here: How to verify that method was NOT called in Moq?
edit:
I simulated the exact scenario that you are seeing and I have narrowed it down to the data type that you are iterating over. Due to the fact that you are using a list I would guess there is some internal workings of the list that are causing this problem. I changed all the list references to arrays and the branch coverage returned as expected.

NUnit async tests fail after merge

NUnit 2.6.4.
I have a VS/C# project that introduces async methods. It has many tests like this that pass:
[Test]
public async void NullProcThrows_Async()
{
var keyList = new KeyList<int>();
Assert.Throws<ArgumentNullException>(async () => await keyList.LoadAsync((IDBProcedure)null, "ID", CancellationToken.None));
}
I have merged this into our trunk (no conflicts) and now this test fails. I am trying to figure out the difference.
When I trace the code in the trunk I see two exceptions thrown:
The first is the ArgumentNullException I am expecting.
The second is
NUnit.Framework.AssertionException saying Expected
<System.ArgumentNullException> But was: null
When I run the test on the branch version I only see the one exception and the test passes.
What could be different between the two projects?
There seems to be a few issues with the code provided, consider the following:
[Test, ExpectedException(typeof(ArgumentNullException)]
public async Task NullProcThrows_Async()
{
var keyList = new KeyList<int>();
await keyList.LoadAsync((IDBProcedure)null, "ID", CancellationToken.None);
Assert.Fail("This should never be executed as we expected the above to throw.");
}
According to the NUnit documentation, you should be using the ExpectedException attribute instead of Assert.Throws. So I added that attribute and then remove the Assert.Throws and instead add Assert.Fail. Also, I made the method Task returning and this prevented the async void. Finally, doing it this way prevents the async lambda.

In MSTest How to access TestMethod exception in TestCleanup without using try/catch block in test method

[TestInitialize]
public void SetUp()
{
//Do required actions before every test
}
[TestMethod]
public void Test1()
{
//Actual test
Assert.AreEqual(1, 0);
}
[TestCleanup]
public void TearDown()
{
//If TestMethod has failed - Get the exeception thrown by the TestMethod. So based on this I can take some action?
}
I am able to get TestMethod Name, Test outcome from TestContext. However I want to get the stacktrace of TestMethod in TestCleanup.
Secondly I know one way of achiving this is by wraping test method steps in a try / catch block and setting the exception to a variable or a property and acessing it in tear down.
However I do not want to wrap each and every testmethod in try/catch block. Is there any other cleaner approach available?
I would appriciate a little detailed explaination or an example as I am a novice in MSTest and programming.

Second Unit Test Not Running

I am having trouble getting my Method B test to run. The logic is fine, but when the unit tests are run, only Method A will run. If Method A and B are switched in terms of spots, only Method B will run. So clearly the code is wrong at some point. Do I need to call method B's test from inside method A in order to get both unit tests to run?
I'm pretty new to C#, so forgive my basic question.
using redacted;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
namespace UnitTests
{
[TestClass()]
public class ClassTest
{
public TestContext TestContext{get;set;}
[TestMethod()]
public void MethodATest()
{
the unit test
}
[TestMethod()]
public void MethodBTest()
{
the unit test
}
}
}
Looks fine.
Make sure you are running all test (Test->Run->All tests), not something like test in context (Ctrl+R, T) or have some sort of list of tests to run.

Categories

Resources