Skip to content

Commit 202ceb3

Browse files
committed
feat!: Invoke async message scenario factories on request
We still have to invoke the factory with sync-over-async at request time and this puts a burden on the user not to use this improperly, but if we want to delay invocation of the factory until after provider states have been configured then this is the first step. This is also obviously a breaking API change and requires a major version bump. `WithAsyncContent` makes way more sense because it's the content factory that's async, not the call to the builder as `WithContentAsync` would imply. This also means the return type changes to void instead of Task. See #459
1 parent b3c2fe1 commit 202ceb3

File tree

6 files changed

+32
-51
lines changed

6 files changed

+32
-51
lines changed

src/PactNet.Abstractions/Verifier/Messaging/IMessageScenarioBuilder.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,29 @@ public interface IMessageScenarioBuilder
1717
IMessageScenarioBuilder WithMetadata(dynamic metadata);
1818

1919
/// <summary>
20-
/// Set the action of the scenario
20+
/// Set the content factory of the scenario. The factory is invoked each time the scenario is required.
2121
/// </summary>
2222
/// <param name="factory">Content factory</param>
2323
void WithContent(Func<dynamic> factory);
2424

2525
/// <summary>
26-
/// Set the content of the scenario
26+
/// Set the content factory of the scenario. The factory is invoked each time the scenario is required.
2727
/// </summary>
2828
/// <param name="factory">Content factory</param>
2929
/// <param name="settings">Custom JSON serializer settings</param>
3030
void WithContent(Func<dynamic> factory, JsonSerializerOptions settings);
3131

3232
/// <summary>
33-
/// Set the action of the scenario
33+
/// Set the content factory of the scenario. The factory is invoked each time the scenario is required.
3434
/// </summary>
3535
/// <param name="factory">Content factory</param>
36-
Task WithContentAsync(Func<Task<dynamic>> factory);
36+
void WithAsyncContent(Func<Task<dynamic>> factory);
3737

3838
/// <summary>
39-
/// Set the content of the scenario
39+
/// Set the content factory of the scenario. The factory is invoked each time the scenario is required.
4040
/// </summary>
4141
/// <param name="factory">Content factory</param>
4242
/// <param name="settings">Custom JSON serializer settings</param>
43-
Task WithContentAsync(Func<Task<dynamic>> factory, JsonSerializerOptions settings);
43+
void WithAsyncContent(Func<Task<dynamic>> factory, JsonSerializerOptions settings);
4444
}
4545
}

src/PactNet.Abstractions/Verifier/Messaging/IMessageScenarios.cs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Threading.Tasks;
43

54
namespace PactNet.Verifier.Messaging
65
{
@@ -22,19 +21,11 @@ public interface IMessageScenarios
2221
IMessageScenarios Add(string description, Func<dynamic> factory);
2322

2423
/// <summary>
25-
/// Add a message scenario
24+
/// Add a message scenario by configuring a scenario builder
2625
/// </summary>
2726
/// <param name="description">Scenario description</param>
2827
/// <param name="configure">Scenario configure</param>
29-
/// <returns></returns>
28+
/// <returns>Fluent builder</returns>
3029
IMessageScenarios Add(string description, Action<IMessageScenarioBuilder> configure);
31-
32-
/// <summary>
33-
/// Add a message scenario
34-
/// </summary>
35-
/// <param name="description">Scenario description</param>
36-
/// <param name="configure">Scenario configure</param>
37-
/// <returns></returns>
38-
IMessageScenarios Add(string description, Func<IMessageScenarioBuilder, Task> configure);
3930
}
4031
}

src/PactNet/Verifier/Messaging/MessageScenarioBuilder.cs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace PactNet.Verifier.Messaging
1010
internal class MessageScenarioBuilder : IMessageScenarioBuilder
1111
{
1212
private readonly string description;
13+
1314
private Func<dynamic> factory;
1415
private dynamic metadata = new { ContentType = "application/json" };
1516
private JsonSerializerOptions settings;
@@ -55,25 +56,32 @@ public void WithContent(Func<dynamic> factory, JsonSerializerOptions settings)
5556
}
5657

5758
/// <summary>
58-
/// Set the action of the scenario
59+
/// Set the content factory of the scenario. The factory is invoked each time the scenario is required.
5960
/// </summary>
6061
/// <param name="factory">Content factory</param>
61-
public async Task WithContentAsync(Func<Task<dynamic>> factory)
62+
public void WithAsyncContent(Func<Task<dynamic>> factory)
6263
{
63-
dynamic value = await factory();
64-
this.factory = () => value;
64+
if (factory == null)
65+
{
66+
throw new ArgumentNullException(nameof(factory));
67+
}
68+
69+
this.WithContent(() => factory().GetAwaiter().GetResult());
6570
}
6671

6772
/// <summary>
68-
/// Set the content of the scenario
73+
/// Set the content factory of the scenario. The factory is invoked each time the scenario is required.
6974
/// </summary>
7075
/// <param name="factory">Content factory</param>
7176
/// <param name="settings">Custom JSON serializer settings</param>
72-
public async Task WithContentAsync(Func<Task<dynamic>> factory, JsonSerializerOptions settings)
77+
public void WithAsyncContent(Func<Task<dynamic>> factory, JsonSerializerOptions settings)
7378
{
74-
dynamic value = await factory();
75-
this.factory = () => value;
76-
this.settings = settings;
79+
if (factory == null)
80+
{
81+
throw new ArgumentNullException(nameof(factory));
82+
}
83+
84+
this.WithContent(() => factory().GetAwaiter().GetResult(), settings);
7785
}
7886

7987
/// <summary>

src/PactNet/Verifier/Messaging/MessageScenarios.cs

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Collections.ObjectModel;
4-
using System.Threading.Tasks;
54

65
namespace PactNet.Verifier.Messaging
76
{
@@ -44,11 +43,11 @@ public IMessageScenarios Add(string description, Func<dynamic> factory)
4443
}
4544

4645
/// <summary>
47-
/// Add a message scenario
46+
/// Add a message scenario by configuring a scenario builder
4847
/// </summary>
4948
/// <param name="description">Scenario description</param>
5049
/// <param name="configure">Scenario configure</param>
51-
/// <returns></returns>
50+
/// <returns>Fluent builder</returns>
5251
public IMessageScenarios Add(string description, Action<IMessageScenarioBuilder> configure)
5352
{
5453
var builder = new MessageScenarioBuilder(description);
@@ -59,22 +58,5 @@ public IMessageScenarios Add(string description, Action<IMessageScenarioBuilder>
5958

6059
return this;
6160
}
62-
63-
/// <summary>
64-
/// Add a message scenario
65-
/// </summary>
66-
/// <param name="description">Scenario description</param>
67-
/// <param name="configure">Scenario configure</param>
68-
/// <returns></returns>
69-
public IMessageScenarios Add(string description, Func<IMessageScenarioBuilder, Task> configure)
70-
{
71-
var builder = new MessageScenarioBuilder(description);
72-
configure?.Invoke(builder).GetAwaiter().GetResult();
73-
74-
Scenario scenario = builder.Build();
75-
this.scenarios.Add(description, scenario);
76-
77-
return this;
78-
}
7961
}
8062
}

tests/PactNet.Tests/Verifier/Messaging/MessageScenarioBuilderTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,22 +64,22 @@ public void WithContent_WithCustomSettings_SetsSettings()
6464
}
6565

6666
[Fact]
67-
public async Task WithContentAsync_WhenCalled_SetsContent()
67+
public void WithAsyncContent_WhenCalled_SetsContent()
6868
{
6969
dynamic expected = new { Foo = 42 };
7070

71-
await this.builder.WithContentAsync(() => Task.FromResult<dynamic>(expected));
71+
this.builder.WithAsyncContent(() => Task.FromResult<dynamic>(expected));
7272
object actual = this.builder.Build().Invoke();
7373

7474
actual.Should().Be(expected);
7575
}
7676

7777
[Fact]
78-
public async Task WithContentAsync_WithCustomSettings_SetsSettings()
78+
public void WithAsyncContent_WithCustomSettings_SetsSettings()
7979
{
8080
var expected = new JsonSerializerOptions();
8181

82-
await this.builder.WithContentAsync(() => Task.FromResult<dynamic>(new { Foo = "Bar" }), expected);
82+
this.builder.WithAsyncContent(() => Task.FromResult<dynamic>(new { Foo = "Bar" }), expected);
8383
var actual = this.builder.Build().JsonSettings;
8484

8585
actual.Should().Be(expected);

tests/PactNet.Tests/Verifier/Messaging/MessageScenariosTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public void Add_AsyncBuilder_AddsScenario()
5252
Func<Task<dynamic>> factory = () => Task.FromResult<dynamic>(new { Foo = 42 });
5353
JsonSerializerOptions settings = new JsonSerializerOptions();
5454

55-
this.scenarios.Add("description", async builder => await builder.WithMetadata(metadata).WithContentAsync(factory, settings));
55+
this.scenarios.Add("description", builder => builder.WithMetadata(metadata).WithAsyncContent(factory, settings));
5656

5757
this.scenarios.Scenarios.Should().BeEquivalentTo(new Dictionary<string, Scenario>
5858
{

0 commit comments

Comments
 (0)