Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions NSubstitute.sln
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NSubstitute.Acceptance.Spec
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NSubstitute.Benchmarks", "tests\NSubstitute.Benchmarks\NSubstitute.Benchmarks.csproj", "{D2D162D4-EF1D-4B40-8736-9228C2FEA16C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestAsyncEventHandlersWithNSubstiute", "tests\Nsubstitute.TestAsyncEventHandlersWithNSubstiute\TestAsyncEventHandlersWithNSubstiute.csproj", "{F9393821-D811-433C-8642-584F94701F1D}"
Comment thread
jmartschinke marked this conversation as resolved.
Outdated
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -47,6 +49,10 @@ Global
{D2D162D4-EF1D-4B40-8736-9228C2FEA16C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D2D162D4-EF1D-4B40-8736-9228C2FEA16C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D2D162D4-EF1D-4B40-8736-9228C2FEA16C}.Release|Any CPU.Build.0 = Release|Any CPU
{F9393821-D811-433C-8642-584F94701F1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F9393821-D811-433C-8642-584F94701F1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F9393821-D811-433C-8642-584F94701F1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F9393821-D811-433C-8642-584F94701F1D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -55,6 +61,7 @@ Global
{F59BF5FC-52D8-492E-BDE8-244C183B4C92} = {CFB6BF4B-381D-4884-A8E8-D1FA71315BDE}
{8C2300AA-F94C-4005-A359-257C5EAD338E} = {0E2B9095-7548-462F-9BCC-CD6765B3ED60}
{D2D162D4-EF1D-4B40-8736-9228C2FEA16C} = {0E2B9095-7548-462F-9BCC-CD6765B3ED60}
{F9393821-D811-433C-8642-584F94701F1D} = {0E2B9095-7548-462F-9BCC-CD6765B3ED60}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {230E97F1-5246-4D49-8ED9-065F2B154E93}
Expand Down
10 changes: 10 additions & 0 deletions src/NSubstitute/Core/WhenCalled.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Threading.Tasks;
using NSubstitute.Routing;

// Disable nullability for entry-point API
Expand Down Expand Up @@ -35,6 +36,15 @@ public void Do(Action<CallInfo> callbackWithArguments)
}

/// <summary>
/// Perform this action when called.
/// </summary>
/// <param name="callbackWithArguments"></param>
public void Do(Func<CallInfo, Task> callbackWithArguments)
{
Do(callInfo => callbackWithArguments(callInfo).GetAwaiter().GetResult());
}

/// <summary>
/// Perform this configured callback when called.
/// </summary>
/// <param name="callback"></param>
Expand Down
3 changes: 2 additions & 1 deletion src/NSubstitute/Routing/Handlers/RaiseEventHandler.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Reflection;
using System.Threading.Tasks;
using NSubstitute.Core;
using NSubstitute.Exceptions;

Expand Down Expand Up @@ -35,7 +36,7 @@ public RouteAction Handle(ICall call)

try
{
handler.DynamicInvoke(eventArguments);
(handler.DynamicInvoke(eventArguments) as Task)?.GetAwaiter().GetResult();
}
catch (TargetInvocationException e)
{
Expand Down
25 changes: 24 additions & 1 deletion tests/NSubstitute.Acceptance.Specs/WhenCalledDo.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using NSubstitute.Acceptance.Specs.Infrastructure;
using NSubstitute.Core;
using NUnit.Framework;
Expand All @@ -9,11 +12,31 @@ public class WhenCalledDo
{
private ISomething _something;


[Test]
public void Execute_when_called_async()
{
var called = false;
_something.When(substitute => substitute.Echo(1)).Do(async info =>
{
await Task.Delay(100);
called = true;
});

Assert.That(called, Is.False, "Called");
_something.Echo(1);
Assert.That(called, Is.True, "Called");
}

[Test]
public void Execute_when_called()
{
var called = false;
_something.When(substitute => substitute.Echo(1)).Do(info => called = true);
_something.When(substitute => substitute.Echo(1)).Do(info =>
{
Thread.Sleep(100);
called = true;
});

Assert.That(called, Is.False, "Called");
_something.Echo(1);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using NSubstitute;
using NUnit.Framework;

namespace TestAsyncEventHandlersWithNSubstiute;

[TestFixture]
public class AsyncEventHandlersWithNSubstituteTests
{
[SetUp]
public void SetUp()
{
_waitFinished = false;
}

private bool _waitFinished;

[Test]
public void TestWithSynchronousHandler()
{
var testInterface = Substitute.For<ITestInterface>();

testInterface.TestEvent += SynchronousEventHandler;

testInterface.TestEvent += Raise.Event<TestEventHandler>();

TestContext.WriteLine("Raise.Event finished");

Assert.That(_waitFinished, Is.True);
}

[Test]
public async Task TestSubstituteImplementationWithSynchronousHandler()
{
var testImplementation = new TestImplementation();

testImplementation.TestEvent += SynchronousEventHandler;

await testImplementation.RaiseEventAsync();

TestContext.WriteLine("Raise.Event finished");

Assert.That(_waitFinished, Is.True);
}

private Task SynchronousEventHandler()
{
TestContext.WriteLine("starting to wait");
Thread.Sleep(100);
_waitFinished = true;
TestContext.WriteLine("wait finished");
return Task.CompletedTask;
}


[Test]
public void TestSubstituteWithAsynchronousHandler()
{
var testInterface = Substitute.For<ITestInterface>();

testInterface.TestEvent += AsynchronousEventHandler;

testInterface.TestEvent += Raise.Event<TestEventHandler>();

TestContext.WriteLine("Raise.Event finished");

Assert.That(_waitFinished, Is.True);
}

private async Task AsynchronousEventHandler()
{
TestContext.WriteLine("starting to wait");
await Task.Delay(100);
_waitFinished = true;
TestContext.WriteLine("wait finished");
}


[Test]
public async Task TestImplementationWithAsynchronousHandler()
{
var testImplementation = new TestImplementation();

testImplementation.TestEvent += AsynchronousEventHandler;

await testImplementation.RaiseEventAsync();

TestContext.WriteLine("Raise.Event finished");

Assert.That(_waitFinished, Is.True);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace TestAsyncEventHandlersWithNSubstiute;

public delegate Task TestEventHandler();

public interface ITestInterface
{
event TestEventHandler TestEvent;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="NUnit" Version="3.14.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\NSubstitute\NSubstitute.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace TestAsyncEventHandlersWithNSubstiute
{

public class TestImplementation : ITestInterface
{
public event TestEventHandler? TestEvent;

public async Task RaiseEventAsync()
{
if (TestEvent != null) await TestEvent();
}
}
}