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.
Related
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.
I have a step class that has steps required to call async API and assert against it. Currently it looks like that:
[Given(#"a setting from API is correct")]
public async void GetSetting()
{
var setting = (await GetSettingsFromApi).Setting;
Assert.IsTrue(setting);
}
There are couple problems here:
I need this step to be performed at the correct time - after the previous and before the following, unsurprisingly. They can be sync or async, but they don't await each other. Making sure it's executed exactly first would also do. Is there a way to achieve it? Beside hardcoding all steps to explicitly await each other?
Assert failure exception is suppressed - it is shown in the in the debugger, but scenario is not stopped and failed as it should? Can I make it pass through and fail the test when the await result is received? This one is actually more important - if test is failed correctly on assert it's doesn't matter if that happens a bit later than expected.
I am using the testing framework that comes with Visual Studio, along with NSubstitute to unit test a method that takes a system ID, and throws an exception if the system can't be found in the database...
public VRTSystem GetSystem(int systemID)
{
VRTSystem system = VrtSystemsRepository.GetVRTSystemByID(systemID);
if (system == null)
{
throw new Exception("System not found");
}
return system;
}
(In case this seems odd, there is a specific business case for this method that requires it to throw an exception, as returning a null system is not acceptable for its usage)
I want to write a test to check that an exception is thrown if the system doesn't exist. I currently have the following...
[TestMethod]
public void LicensingApplicationServiceBusinessLogic_GetSystem_SystemDoesntExist()
{
var bll = new LicensingApplicationServiceBusinessLogic();
try
{
VRTSystem systemReturned = bll.GetSystem(613);
Assert.Fail("Should have thrown an exception, but didn't.);
}
catch () { }
}
By not mocking the repository, the system returned by VrtSystemsRepository.GetVRTSystemByID() will be null, and the exception thrown. Whilst this works, it looks wrong to me. I wouldn't have expected to need a try/catch block in a test.
The NSubstitute docs have an example that implies I should be able to test this as follows...
[TestMethod]
public void GetSystem_SystemDoesntExist()
{
var bll = new LicensingApplicationServiceBusinessLogic();
Assert.Throws<Exception>(() => bll.GetSystem(613));
}
However, if I try this in my test code, I get Throws highlighted in red, with the error message "Assert does not contain definition for Throws"
Now, I'm not actually sure that the sample on that page covers my scenario, as the test code specifies that the method under test throws an exception, which I don't really understand, as I thought the idea of testing was to leave the method under test alone, and test what happens under various scenarios. However, even without that, I don't understand why the Assert.Throws method doesn't exist.
Anyone any ideas?
Edit: DavidG pointed out that Assert.Throws is probably part of NUnit, not the MS framework, which would explain why it's not recognised. If so, is the way I'm currently testing the right way to do it?
As mentioned by DavidG The referenced documentation is using NUnit for assertions.
If not using that framework you can use the ExpectedExceptionAttribute Class
[TestMethod]
[ExpectedException(typeof(<<Your expected exception here>>))]
public void GetSystem_SystemDoesntExist() {
var bll = new LicensingApplicationServiceBusinessLogic();
bll.GetSystem(613);
}
which would fail if the expected exception is not thrown.
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.
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.