diff --git a/src/core/Akka.Remote.Tests/Transport/AkkaProtocolSpec.cs b/src/core/Akka.Remote.Tests/Transport/AkkaProtocolSpec.cs index 4a87a588930..1996822dd1b 100644 --- a/src/core/Akka.Remote.Tests/Transport/AkkaProtocolSpec.cs +++ b/src/core/Akka.Remote.Tests/Transport/AkkaProtocolSpec.cs @@ -423,11 +423,7 @@ public void ProtocolStateActor_must_give_up_outbound_after_connection_timeout() Watch(stateActor); - // inner exception will be a TimeoutException - Intercept(() => - { - statusPromise.Task.Wait(TimeSpan.FromSeconds(5)).Should().BeTrue(); - }); + Intercept(() => statusPromise.Task.Wait(TimeSpan.FromSeconds(5)).Should().BeTrue()); ExpectTerminated(stateActor); } diff --git a/src/core/Akka.Streams.Tests/Dsl/FlowAskSpec.cs b/src/core/Akka.Streams.Tests/Dsl/FlowAskSpec.cs index 7a5999c128a..c9309ec143e 100644 --- a/src/core/Akka.Streams.Tests/Dsl/FlowAskSpec.cs +++ b/src/core/Akka.Streams.Tests/Dsl/FlowAskSpec.cs @@ -266,13 +266,11 @@ public void Flow_with_ask_signal_failure_when_target_actor_is_terminated() => th .Ask(r, _timeout, 4) .RunWith(Sink.Ignore(), _materializer); - Intercept(() => + Intercept(() => { r.Tell(PoisonPill.Instance); done.Wait(RemainingOrDefault); - }) - .Flatten() - .InnerException.Should().BeOfType(); + }); }, _materializer); diff --git a/src/core/Akka.Tests.Shared.Internals/AkkaSpec.cs b/src/core/Akka.Tests.Shared.Internals/AkkaSpec.cs index 9b6a2c94e7f..e82ca53eca6 100644 --- a/src/core/Akka.Tests.Shared.Internals/AkkaSpec.cs +++ b/src/core/Akka.Tests.Shared.Internals/AkkaSpec.cs @@ -113,7 +113,7 @@ private static string GetCallerName() } public static Config AkkaSpecConfig { get { return _akkaSpecConfig; } } - + protected T ExpectMsgPf(TimeSpan? timeout, string hint, Func function) { MessageEnvelope envelope; @@ -136,30 +136,88 @@ protected T ExpectMsgPf(string hint, Func pf) return pf.Invoke(t); } - + /// + /// Intercept and return an exception that's expected to be thrown by the passed function value. The thrown + /// exception must be an instance of the type specified by the type parameter of this method. This method + /// invokes the passed function. If the function throws an exception that's an instance of the specified type, + /// this method returns that exception. Else, whether the passed function returns normally or completes abruptly + /// with a different exception, this method throws . + /// + /// Also note that the difference between this method and is that this method + /// returns the expected exception, so it lets you perform further assertions on that exception. By contrast, + /// the indicates to the reader of the code that nothing further is expected + /// about the thrown exception other than its type. The recommended usage is to use + /// by default, intercept only when you need to inspect the caught exception further. + /// + /// + /// The action that should throw the expected exception + /// The intercepted exception, if it is of the expected type + /// If the passed action does not complete abruptly with an exception that's an instance of the specified type. protected T Intercept(Action actionThatThrows) where T : Exception { - return Assert.Throws(() => actionThatThrows()); - } + try + { + actionThatThrows(); + } + catch (Exception ex) + { + var exception = ex is AggregateException aggregateException + ? aggregateException.Flatten().InnerExceptions[0] + : ex; + + var exceptionType = typeof(T); + return exceptionType == exception.GetType() + ? (T)exception + : throw new ThrowsException(exceptionType, exception); + } - protected void Intercept(Action actionThatThrows) + throw new ThrowsException(typeof(T)); + } + + /// + /// Ensure that an expected exception is thrown by the passed function value. The thrown exception must be an + /// instance of the type specified by the type parameter of this method. This method invokes the passed + /// function. If the function throws an exception that's an instance of the specified type, this method returns + /// void. Else, whether the passed function returns normally or completes abruptly with a different + /// exception, this method throws . + /// + /// Also note that the difference between this method and is that this method + /// does not return the expected exception, so it does not let you perform further assertions on that exception. + /// It also indicates to the reader of the code that nothing further is expected about the thrown exception + /// other than its type. The recommended usage is to use by default, + /// only when you need to inspect the caught exception further. + /// + /// + /// The action that should throw the expected exception + /// If the passed action does not complete abruptly with an exception that's an instance of the specified type. + protected void AssertThrows(Action actionThatThrows) where T : Exception { try { actionThatThrows(); } - catch(Exception) + catch (Exception ex) { - return; + var exception = ex is AggregateException aggregateException + ? aggregateException.Flatten().InnerExceptions[0] + : ex; + + var exceptionType = typeof(T); + if (exceptionType == exception.GetType()) + return; + + throw new ThrowsException(exceptionType, exception); } - throw new ThrowsException(typeof(Exception)); + + throw new ThrowsException(typeof(T)); } - - protected async Task InterceptAsync(Func asyncActionThatThrows) + + [Obsolete("Use AssertThrows instead.")] + protected void Intercept(Action actionThatThrows) { try { - await asyncActionThatThrows(); + actionThatThrows(); } catch(Exception) { @@ -168,24 +226,6 @@ protected async Task InterceptAsync(Func asyncActionThatThrows) throw new ThrowsException(typeof(Exception)); } - [Obsolete("Use Intercept instead. This member will be removed.")] - protected void intercept(Action actionThatThrows) where T : Exception - { - Assert.Throws(() => actionThatThrows()); - } - - [Obsolete("Use ExpectMsgPf instead. This member will be removed.")] - protected T expectMsgPF(string hint, Func pf) - { - return ExpectMsgPf(hint, pf); - } - - [Obsolete("Use ExpectMsgPf instead. This member will be removed.")] - protected T expectMsgPF(TimeSpan duration, string hint, Func pf) - { - return ExpectMsgPf(duration, hint, pf); - } - protected void MuteDeadLetters(params Type[] messageClasses) { if (!Sys.Log.IsDebugEnabled) diff --git a/src/core/Akka.Tests/Actor/CoordinatedShutdownSpec.cs b/src/core/Akka.Tests/Actor/CoordinatedShutdownSpec.cs index ac352e677b3..6fe34ceae13 100644 --- a/src/core/Akka.Tests/Actor/CoordinatedShutdownSpec.cs +++ b/src/core/Akka.Tests/Actor/CoordinatedShutdownSpec.cs @@ -337,18 +337,7 @@ public void CoordinatedShutdown_must_abort_if_recover_is_off() var result = co.Run(CoordinatedShutdown.UnknownReason.Instance); ExpectMsg("B"); - Intercept(() => - { - if (result.Wait(RemainingOrDefault)) - { - result.Exception?.Flatten().InnerException.Should().BeOfType(); - } - else - { - throw new Exception("CoordinatedShutdown task did not complete"); - } - }); - + Intercept(() => result.Wait(RemainingOrDefault)); ExpectNoMsg(TimeSpan.FromMilliseconds(200)); // C not run }