Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try to stabilize UIFact tests by running them sequentially #1902

Merged
merged 1 commit into from Apr 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -84,17 +84,21 @@ public async Task When_async_method_throws_an_empty_AggregateException_it_should
await act2.Should().ThrowAsync<XunitException>();
}

[UIFact]
public async Task When_async_method_throws_an_empty_AggregateException_on_UI_thread_it_should_fail()
[Collection("UIFacts")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure that tests within the same class will never run in parallel. So moving all those tests in the same (partial) class should be enough.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change should also put tests across different classes in the same test collection to avoid any UIFacts being run in parallel.

public partial class UIFacts
{
// Arrange
Func<Task> act = () => throw new AggregateException();
[UIFact]
public async Task When_async_method_throws_an_empty_AggregateException_on_UI_thread_it_should_fail()
{
// Arrange
Func<Task> act = () => throw new AggregateException();

// Act
Func<Task> act2 = () => act.Should().NotThrowAsync();
// Act
Func<Task> act2 = () => act.Should().NotThrowAsync();

// Assert
await act2.Should().ThrowAsync<XunitException>();
// Assert
await act2.Should().ThrowAsync<XunitException>();
}
}

[Fact]
Expand All @@ -107,14 +111,17 @@ public async Task When_async_method_throws_a_nested_AggregateException_it_should
await act.Should().ThrowAsync<ArgumentException>().WithMessage("That was wrong.");
}

[UIFact]
public async Task When_async_method_throws_a_nested_AggregateException_on_UI_thread_it_should_provide_the_message()
public partial class UIFacts
{
// Arrange
Func<Task> act = () => throw new AggregateException(new ArgumentException("That was wrong."));
[UIFact]
public async Task When_async_method_throws_a_nested_AggregateException_on_UI_thread_it_should_provide_the_message()
{
// Arrange
Func<Task> act = () => throw new AggregateException(new ArgumentException("That was wrong."));

// Act & Assert
await act.Should().ThrowAsync<ArgumentException>().WithMessage("That was wrong.");
// Act & Assert
await act.Should().ThrowAsync<ArgumentException>().WithMessage("That was wrong.");
}
}

[Fact]
Expand Down Expand Up @@ -499,17 +506,20 @@ public async Task When_async_method_does_not_throw_async_exception_and_that_was_
await action.Should().NotThrowAsync();
}

[UIFact]
public async Task When_async_method_does_not_throw_async_exception_on_UI_thread_and_that_was_expected_it_should_succeed()
public partial class UIFacts
{
// Arrange
var asyncObject = new AsyncClass();
[UIFact]
public async Task When_async_method_does_not_throw_async_exception_on_UI_thread_and_that_was_expected_it_should_succeed()
{
// Arrange
var asyncObject = new AsyncClass();

// Act
Func<Task> action = () => asyncObject.SucceedAsync();
// Act
Func<Task> action = () => asyncObject.SucceedAsync();

// Assert
await action.Should().NotThrowAsync();
// Assert
await action.Should().NotThrowAsync();
}
}

[Fact]
Expand Down Expand Up @@ -605,17 +615,20 @@ public async Task When_subject_throws_expected_async_exact_exception_it_should_s
await action.Should().ThrowExactlyAsync<ArgumentException>("because {0} should do that", "IFoo.Do");
}

[UIFact]
public async Task When_subject_throws_on_UI_thread_expected_async_exact_exception_it_should_succeed()
public partial class UIFacts
{
// Arrange
var asyncObject = new AsyncClass();
[UIFact]
public async Task When_subject_throws_on_UI_thread_expected_async_exact_exception_it_should_succeed()
{
// Arrange
var asyncObject = new AsyncClass();

// Act
Func<Task> action = () => asyncObject.ThrowAsync<ArgumentException>();
// Act
Func<Task> action = () => asyncObject.ThrowAsync<ArgumentException>();

// Assert
await action.Should().ThrowExactlyAsync<ArgumentException>("because {0} should do that", "IFoo.Do");
// Assert
await action.Should().ThrowExactlyAsync<ArgumentException>("because {0} should do that", "IFoo.Do");
}
}

[Fact]
Expand Down Expand Up @@ -1205,34 +1218,37 @@ await action.Should().ThrowAsync<XunitException>()
.WithMessage("Did not expect any exceptions after 2s because we passed valid arguments*");
}

[UIFact]
public async Task When_no_exception_should_be_thrown_on_UI_thread_for_async_func_after_wait_time_but_it_was_it_should_throw()
public partial class UIFacts
{
// Arrange
var waitTime = 2.Seconds();
var pollInterval = 10.Milliseconds();
[UIFact]
public async Task When_no_exception_should_be_thrown_on_UI_thread_for_async_func_after_wait_time_but_it_was_it_should_throw()
{
// Arrange
var waitTime = 2.Seconds();
var pollInterval = 10.Milliseconds();

var clock = new FakeClock();
var timer = clock.StartTimer();
clock.CompleteAfter(waitTime);
var clock = new FakeClock();
var timer = clock.StartTimer();
clock.CompleteAfter(waitTime);

Func<Task> throwLongerThanWaitTime = async () =>
{
if (timer.Elapsed <= waitTime.Multiply(1.5))
Func<Task> throwLongerThanWaitTime = async () =>
{
throw new ArgumentException("An exception was forced");
}
if (timer.Elapsed <= waitTime.Multiply(1.5))
{
throw new ArgumentException("An exception was forced");
}

await Task.Yield();
};
await Task.Yield();
};

// Act
Func<Task> action = () => throwLongerThanWaitTime.Should(clock)
.NotThrowAfterAsync(waitTime, pollInterval, "we passed valid arguments");
// Act
Func<Task> action = () => throwLongerThanWaitTime.Should(clock)
.NotThrowAfterAsync(waitTime, pollInterval, "we passed valid arguments");

// Assert
await action.Should().ThrowAsync<XunitException>()
.WithMessage("Did not expect any exceptions after 2s because we passed valid arguments*");
// Assert
await action.Should().ThrowAsync<XunitException>()
.WithMessage("Did not expect any exceptions after 2s because we passed valid arguments*");
}
}

[Fact]
Expand Down Expand Up @@ -1263,32 +1279,35 @@ public async Task When_no_exception_should_be_thrown_for_async_func_after_wait_t
await act.Should().NotThrowAsync();
}

[UIFact]
public async Task When_no_exception_should_be_thrown_on_UI_thread_for_async_func_after_wait_time_and_none_was_it_should_not_throw()
public partial class UIFacts
{
// Arrange
var waitTime = 6.Seconds();
var pollInterval = 10.Milliseconds();
[UIFact]
public async Task When_no_exception_should_be_thrown_on_UI_thread_for_async_func_after_wait_time_and_none_was_it_should_not_throw()
{
// Arrange
var waitTime = 6.Seconds();
var pollInterval = 10.Milliseconds();

var clock = new FakeClock();
var timer = clock.StartTimer();
clock.Delay(waitTime);
var clock = new FakeClock();
var timer = clock.StartTimer();
clock.Delay(waitTime);

Func<Task> throwShorterThanWaitTime = async () =>
{
if (timer.Elapsed <= waitTime.Divide(12))
Func<Task> throwShorterThanWaitTime = async () =>
{
throw new ArgumentException("An exception was forced");
}
if (timer.Elapsed <= waitTime.Divide(12))
{
throw new ArgumentException("An exception was forced");
}

await Task.Yield();
};
await Task.Yield();
};

// Act
Func<Task> act = () => throwShorterThanWaitTime.Should(clock).NotThrowAfterAsync(waitTime, pollInterval);
// Act
Func<Task> act = () => throwShorterThanWaitTime.Should(clock).NotThrowAfterAsync(waitTime, pollInterval);

// Assert
await act.Should().NotThrowAsync();
// Assert
await act.Should().NotThrowAsync();
}
}
#endregion
}
Expand Down
30 changes: 17 additions & 13 deletions Tests/FluentAssertions.Specs/Execution/CallerIdentifierSpecs.cs
Expand Up @@ -455,20 +455,24 @@ public void When_the_method_has_Should_prefix_it_should_read_whole_method()
.WithMessage("Expected foo.ShouldReturnSomeBool() to be false*");
}

[UIFact]
public async Task Caller_identification_should_also_work_for_statements_following_async_code()
[Collection("UIFacts")]
public partial class UIFacts
{
// Arrange
const string someText = "Hello";
Func<Task> task = async () => await Task.Yield();

// Act
await task.Should().NotThrowAsync();
Action act = () => someText.Should().Be("Hi");

// Assert
act.Should().Throw<XunitException>()
.WithMessage("*someText*", "it should capture the variable name");
[UIFact]
public async Task Caller_identification_should_also_work_for_statements_following_async_code()
{
// Arrange
const string someText = "Hello";
Func<Task> task = async () => await Task.Yield();

// Act
await task.Should().NotThrowAsync();
Action act = () => someText.Should().Be("Hi");

// Assert
act.Should().Throw<XunitException>()
.WithMessage("*someText*", "it should capture the variable name");
}
}

[Fact]
Expand Down
77 changes: 42 additions & 35 deletions Tests/FluentAssertions.Specs/Specialized/TaskAssertionSpecs.cs
Expand Up @@ -79,20 +79,24 @@ public async Task Sync_work_in_async_method_is_taken_into_account()
await action.Should().ThrowAsync<XunitException>();
}

[UIFact]
public async Task When_task_completes_on_UI_thread_fast_async_it_should_succeed()
[Collection("UIFacts")]
public partial class UIFacts
{
// Arrange
var timer = new FakeClock();
var taskFactory = new TaskCompletionSource<bool>();
[UIFact]
public async Task When_task_completes_on_UI_thread_fast_async_it_should_succeed()
{
// Arrange
var timer = new FakeClock();
var taskFactory = new TaskCompletionSource<bool>();

// Act
Func<Task> action = () => taskFactory.Awaiting(t => (Task)t.Task).Should(timer).CompleteWithinAsync(100.Milliseconds());
taskFactory.SetResult(true);
timer.Complete();
// Act
Func<Task> action = () => taskFactory.Awaiting(t => (Task)t.Task).Should(timer).CompleteWithinAsync(100.Milliseconds());
taskFactory.SetResult(true);
timer.Complete();

// Assert
await action.Should().NotThrowAsync();
// Assert
await action.Should().NotThrowAsync();
}
}

[Fact]
Expand All @@ -110,37 +114,40 @@ public async Task When_task_completes_slow_async_it_should_fail()
await action.Should().ThrowAsync<XunitException>();
}

[UIFact]
public async Task When_task_completes_on_UI_thread_slow_async_it_should_fail()
public partial class UIFacts
{
// Arrange
var timer = new FakeClock();
var taskFactory = new TaskCompletionSource<bool>();
[UIFact]
public async Task When_task_completes_on_UI_thread_slow_async_it_should_fail()
{
// Arrange
var timer = new FakeClock();
var taskFactory = new TaskCompletionSource<bool>();

// Act
Func<Task> action = () => taskFactory.Awaiting(t => (Task)t.Task).Should(timer).CompleteWithinAsync(100.Milliseconds());
timer.Complete();
// Act
Func<Task> action = () => taskFactory.Awaiting(t => (Task)t.Task).Should(timer).CompleteWithinAsync(100.Milliseconds());
timer.Complete();

// Assert
await action.Should().ThrowAsync<XunitException>();
}
// Assert
await action.Should().ThrowAsync<XunitException>();
}

[UIFact]
public async Task When_task_is_checking_synchronization_context_on_UI_thread_it_should_succeed()
{
// Arrange
Func<Task> task = CheckContextAsync;
[UIFact]
public async Task When_task_is_checking_synchronization_context_on_UI_thread_it_should_succeed()
{
// Arrange
Func<Task> task = CheckContextAsync;

// Act
Func<Task> action = () => this.Awaiting(x => task()).Should().CompleteWithinAsync(1.Seconds());
// Act
Func<Task> action = () => this.Awaiting(x => task()).Should().CompleteWithinAsync(1.Seconds());

// Assert
await action.Should().NotThrowAsync();
// Assert
await action.Should().NotThrowAsync();

async Task CheckContextAsync()
{
await Task.Delay(1);
SynchronizationContext.Current.Should().NotBeNull();
async Task CheckContextAsync()
{
await Task.Delay(1);
SynchronizationContext.Current.Should().NotBeNull();
}
}
}
}
Expand Down