Skip to content

Commit

Permalink
Add ExecutionTime acception async action
Browse files Browse the repository at this point in the history
  • Loading branch information
krajek committed Oct 4, 2018
1 parent 42ef7d9 commit fc20316
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 7 deletions.
17 changes: 15 additions & 2 deletions Src/FluentAssertions/AssertionExtensions.cs
Expand Up @@ -55,9 +55,9 @@ public static MemberExecutionTime<T> ExecutionTimeOf<T>(this T subject, Expressi
}

/// <summary>
/// Provides methods for asserting the execution time of a method or property.
/// Provides methods for asserting the execution time of an action.
/// </summary>
/// <param name="action">A reference to the method or property to measure the execution time of.</param>
/// <param name="action">An action to measure the execution time of.</param>
/// <returns>
/// Returns an object for asserting that the execution time matches certain conditions.
/// </returns>
Expand All @@ -67,6 +67,19 @@ public static ExecutionTime ExecutionTime(this Action action)
return new ExecutionTime(action);
}

/// <summary>
/// Provides methods for asserting the execution time of an async action.
/// </summary>
/// <param name="action">An async action to measure the execution time of.</param>
/// <returns>
/// Returns an object for asserting that the execution time matches certain conditions.
/// </returns>
[MustUseReturnValue /* do not use Pure because this method executes the action before returning to the caller */]
public static ExecutionTime ExecutionTime(this Func<Task> action)
{
return new ExecutionTime(action);
}

/// <summary>
/// Returns an <see cref="ExecutionTimeAssertions"/> object that can be used to assert the
/// current <see cref="ExecutionTime"/>.
Expand Down
13 changes: 9 additions & 4 deletions Src/FluentAssertions/Specialized/ExecutionTimeAssertions.cs
Expand Up @@ -216,23 +216,28 @@ public class ExecutionTime
/// </summary>
/// <param name="action">The action of which the execution time must be asserted.</param>
public ExecutionTime(Action action)
: this(() => Task.Run(action), "the action")
{
}

public ExecutionTime(Func<Task> action)
: this(action, "the action")
{
}

protected ExecutionTime(Action action, string actionDescription)
protected ExecutionTime(Func<Task> action, string actionDescription)
{
ActionDescription = actionDescription;
stopwatch = new Stopwatch();
IsRunning = true;
Task = Task.Run(() =>
Task = Task.Run(async () =>
{
// move stopwatch as close to action start as possible
// so that we have to get correct time readings
try
{
stopwatch.Start();
action();
await action();
}
catch (Exception exception)
{
Expand Down Expand Up @@ -268,7 +273,7 @@ public class MemberExecutionTime<T> : ExecutionTime
/// <param name="subject">The object that exposes the method or property.</param>
/// <param name="action">A reference to the method or property to measure the execution time of.</param>
public MemberExecutionTime(T subject, Expression<Action<T>> action)
: base(() => action.Compile()(subject), "(" + action.Body + ")")
: base(() => Task.Run(() => action.Compile()(subject)), "(" + action.Body + ")")
{
}
}
Expand Down
43 changes: 42 additions & 1 deletion Tests/Shared.Specs/ExecutionTimeAssertionsSpecs.cs
@@ -1,6 +1,6 @@
using System;
using System.Threading;

using System.Threading.Tasks;
using FluentAssertions.Extensions;
using Xunit;
using Xunit.Sdk;
Expand Down Expand Up @@ -179,6 +179,27 @@ public void When_the_execution_time_of_an_action_is_not_less_than_a_limit__it_sh
"*action should be less than 0.100s, but it required*");
}

[Fact]
public void When_the_execution_time_of_an_async_action_is_not_less_than_a_limit__it_should_throw()
{
//-----------------------------------------------------------------------------------------------------------
// Arrange
//-----------------------------------------------------------------------------------------------------------

Func<Task> someAction = async () => await Task.Delay(TimeSpan.FromMilliseconds(150));

//-----------------------------------------------------------------------------------------------------------
// Act
//-----------------------------------------------------------------------------------------------------------
Action act = () => someAction.ExecutionTime().Should().BeLessThan(100.Milliseconds());

//-----------------------------------------------------------------------------------------------------------
// Assert
//-----------------------------------------------------------------------------------------------------------
act.Should().Throw<XunitException>().WithMessage(
"*action should be less than 0.100s, but it required*");
}

[Fact]
public void When_the_execution_time_of_an_action_is_less_than_a_limit_it_should_not_throw()
{
Expand All @@ -199,6 +220,26 @@ public void When_the_execution_time_of_an_action_is_less_than_a_limit_it_should_
act.Should().NotThrow();
}

[Fact]
public void When_the_execution_time_of_an_async_action_is_less_than_a_limit_it_should_not_throw()
{
//-----------------------------------------------------------------------------------------------------------
// Arrange
//-----------------------------------------------------------------------------------------------------------

Func<Task> someAction = async () => await Task.Delay(TimeSpan.FromMilliseconds(100));

//-----------------------------------------------------------------------------------------------------------
// Act
//-----------------------------------------------------------------------------------------------------------
Action act = () => someAction.ExecutionTime().Should().BeLessThan(1.Seconds());

//-----------------------------------------------------------------------------------------------------------
// Assert
//-----------------------------------------------------------------------------------------------------------
act.Should().NotThrow();
}

[Fact]
public void When_action_runs_indefinitely_it_should_be_stopped_and_throw_if_there_is_less_than_condition()
{
Expand Down

0 comments on commit fc20316

Please sign in to comment.