Skip to content

Commit fd55f8a

Browse files
authored
docs: opentelemetry (#38)
1 parent f5ec297 commit fd55f8a

File tree

4 files changed

+116
-74
lines changed

4 files changed

+116
-74
lines changed

.github/CONTRIBUTING.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,26 @@
33
This project welcomes contributions:
44

55
**Request for support:**
6-
TBD
6+
We do not provide support for this product.
77

88
**Disclose vulnerability:**
9-
Please [create a new security advisory on GitHub](https://github.com/ArwynFr/dotnet-integration-testing/security/advisories)
9+
[Read our security policy](https://github.com/ArwynFr/dotnet-integration-testing/blob/main/.github/SECURITY.md)
10+
[Create a new security advisory on GitHub](https://github.com/ArwynFr/dotnet-integration-testing/security/advisories)
1011

1112
**Report malfunctions:**
12-
[Please create a new issue on GitHub](https://github.com/ArwynFr/dotnet-integration-testing/issues/new/choose)
13+
[Create a new issue on GitHub](https://github.com/ArwynFr/dotnet-integration-testing/issues/new/choose)
1314

1415
**Suggest a feature:**
15-
[Please create a new issue on GitHub](https://github.com/ArwynFr/dotnet-integration-testing/issues/new/choose)
16+
[Create a new issue on GitHub](https://github.com/ArwynFr/dotnet-integration-testing/issues/new/choose)
1617

1718
**Offer some code:**
18-
Please [fork the repository](https://github.com/ArwynFr/dotnet-integration-testing/fork)
19-
and [submit a pull-request](https://github.com/ArwynFr/dotnet-integration-testing/compare)
19+
[Read our definition of done](https://github.com/ArwynFr/dotnet-integration-testing/blob/main/.github/CONTRIBUTING.md#definition-of-done)
20+
[Fork the repository](https://github.com/ArwynFr/dotnet-integration-testing/fork)
21+
[Submit a pull-request](https://github.com/ArwynFr/dotnet-integration-testing/compare)
22+
23+
**Moderate contributions:**
24+
[Read our governance policy](https://github.com/ArwynFr/dotnet-integration-testing/blob/main/.github/GOVERNANCE.md)
25+
This project is not currently appointing new moderators.
2026

2127
## Definition of Done
2228

.github/README.md

Lines changed: 20 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -83,45 +83,23 @@ public class TestBaseDb : IntegrationTestBase<Program, MyDbContext>
8383
}
8484
```
8585

86-
### Fluent specification-based testing
86+
### OpenTelemetry integration
8787

8888
```cs
89-
// Actual code redacted for brievty
90-
// Write a test driver that implements specifications:
91-
private class MySpecDriver(MyDbContext dbContext, HttpClient client) : TestDriverBase<SpecDriver>
89+
public class OpenTelemetryTests(ITestOutputHelper output) : IntegrationTestBase<Program>(output)
9290
{
93-
// Arranges
94-
public async Task ThereIsEntityWithName(string name) { }
95-
public async Task ThereIsNoEntityWithName(string name) { }
96-
97-
// Acts
98-
public async Task ListAllEntities() { }
99-
public async Task FindEntityWithName(string name) { }
100-
public async Task CreateEntity(EntityDetails payload) { }
101-
102-
// Asserts
103-
public async Task ResultShouldBe(string name) { }
104-
public async Task DetailsCountShouldBe(int number) { }
105-
}
91+
// Tell the library which OTEL sources you want to monitor
92+
// Traces from other sources will be ignored
93+
protected override string[] OpenTelemetrySourceNames => ["SourceA", "SourceB"];
10694

107-
public class MySpecTest(ITestOutputHelper output) : TestBaseDb
108-
{
109-
// Write fluent specifiation test:
110-
[Theory, InlineData("ArwynFr")]
111-
public async Task OnTest(string name)
95+
[Fact]
96+
public async Task Otel()
11297
{
113-
await Services.GetRequiredService<MySpecDriver>()
114-
.Given(x => x.ThereIsEntityWithName(name))
115-
.When(x => x.FindEntityWithName(name))
116-
.Then(x => x.ResultShouldBe(name))
117-
.ExecuteAsync();
118-
}
98+
// Call system under test
99+
await Client.GetAsync("/otel");
119100

120-
// Configure DI library
121-
protected override void ConfigureAppServices(IServiceCollection services)
122-
{
123-
base.ConfigureAppServices(services);
124-
services.AddSingleton(_ => new MySpecDriver(Database, Client));
101+
// Assert on the collection of all activities collected
102+
Activities.Any(activity => activity.DisplayName == "Hello").Should().BeTrue();
125103
}
126104
}
127105
```
@@ -131,26 +109,23 @@ public class MySpecTest(ITestOutputHelper output) : TestBaseDb
131109
This project welcomes contributions:
132110

133111
**Request for support:**
134-
TBD
112+
We do not provide support for this product.
135113

136114
**Disclose vulnerability:**
137-
Please [create a new security advisory on GitHub](https://github.com/ArwynFr/dotnet-integration-testing/security/advisories)
138-
\
139-
[Read our security policy](https://github.com/ArwynFr/dotnet-integration-testing/blob/main/.github/SECURITY.md)
115+
[Read our security policy](https://github.com/ArwynFr/dotnet-integration-testing/blob/main/.github/SECURITY.md)
116+
[Create a new security advisory on GitHub](https://github.com/ArwynFr/dotnet-integration-testing/security/advisories)
140117

141118
**Report malfunctions:**
142-
[Please create a new issue on GitHub](https://github.com/ArwynFr/dotnet-integration-testing/issues/new/choose)
119+
[Create a new issue on GitHub](https://github.com/ArwynFr/dotnet-integration-testing/issues/new/choose)
143120

144121
**Suggest a feature:**
145-
[Please create a new issue on GitHub](https://github.com/ArwynFr/dotnet-integration-testing/issues/new/choose)
122+
[Create a new issue on GitHub](https://github.com/ArwynFr/dotnet-integration-testing/issues/new/choose)
146123

147124
**Offer some code:**
148-
Please [fork the repository](https://github.com/ArwynFr/dotnet-integration-testing/fork)
149-
and [submit a pull-request](https://github.com/ArwynFr/dotnet-integration-testing/compare)
150-
\
151-
[Read our definition of done in contributing guidelines](https://github.com/ArwynFr/dotnet-integration-testing/blob/main/.github/CONTRIBUTING.md)
125+
[Read our definition of done](https://github.com/ArwynFr/dotnet-integration-testing/blob/main/.github/CONTRIBUTING.md#definition-of-done)
126+
[Fork the repository](https://github.com/ArwynFr/dotnet-integration-testing/fork)
127+
[Submit a pull-request](https://github.com/ArwynFr/dotnet-integration-testing/compare)
152128

153129
**Moderate contributions:**
130+
[Read our governance policy](https://github.com/ArwynFr/dotnet-integration-testing/blob/main/.github/GOVERNANCE.md)
154131
This project is not currently appointing new moderators.
155-
\
156-
[Read our governance policy](https://github.com/ArwynFr/dotnet-integration-testing/blob/main/.github/GOVERNANCE.md)

.github/SECURITY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
## Supported version
44

55
The latest version of the library is the only one suported.
6+
67
Please update to the latest version before reporting a vulnerability.
78

89
## Bug bounties
910

1011
There is no bug bounty program in place in our organization.
12+
1113
We will not deliver any bounty for reported bugs or vulnerabilities.
1214

1315
## Report vulnerabilities

.github/USAGE.md

Lines changed: 82 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,19 @@ for details on how this library works.
77

88
## Definitions
99

10-
**Tested application**
10+
### Tested application
11+
1112
A dotnet application that you want to test. Also known as the *system
1213
under test* (SUT).
1314

14-
**Entrypoint**
15+
### Entrypoint
16+
1517
A specific class of the tested application that is run when the
1618
application start. For top-level statement applications this is the
1719
`Program` class.
1820

19-
**Test project**
21+
### Test project
22+
2023
A XUnit test project that implements tests and ensures that the tested
2124
application behaves as expected.
2225

@@ -26,9 +29,8 @@ Simply extend the `IntegrationTestBase<TEntryPoint>` class and provide
2629
the entrypoint class you want to test:
2730

2831
```cs
29-
public class MyTest : IntegrationTestBase<Program>
32+
public class MyTest(ITestOutputHelper output) : IntegrationTestBase<Program>(output)
3033
{
31-
public MyTest(ITestOutputHelper output) : base(output) { }
3234
}
3335
```
3436

@@ -37,7 +39,8 @@ public class MyTest : IntegrationTestBase<Program>
3739
You can override the following methods to customize the tested
3840
application:
3941

40-
ConfigureAppConfiguration
42+
### `ConfigureAppConfiguration`
43+
4144
Change the sources for the app configuration. By default, overrides the
4245
application configuration sources with the following (lower overrides
4346
higher):
@@ -47,12 +50,14 @@ higher):
4750
- User secrets associated with the assembly that contains the test class
4851
- Environment variables
4952

50-
ConfigureAppLogging
53+
### `ConfigureAppLogging`
54+
5155
Change the app logging configuration. By default, redirects all logs
5256
(all namespaces and all levels) to the XUnit output helper. If the test
5357
fails, you get all the tested application logs in the test output.
5458

55-
ConfigureAppServices
59+
### `ConfigureAppServices`
60+
5661
Override dependency injection services of the tested application.
5762

5863
If your test code and the tested application need to access the same
@@ -69,21 +74,16 @@ protected override void ConfigureAppServices(IServiceCollection services)
6974
[Fact]
7075
public async Task OnTest()
7176
{
72-
var expected = 3;
73-
7477
// Access the injected service from the test code
7578
var service = Services.GetRequiredService<IMyService>();
7679
service.SetValue(expected);
77-
78-
var response = await Client.GetFromJsonAsync<int>($"/value");
79-
80-
response.Should().Be(expected);
8180
}
8281
```
8382

8483
## Accessing the tested application
8584

86-
Client
85+
### `Client`
86+
8787
You can access the tested application using the `Client` property which
8888
returns a pseudo `HttpClient` created by `WebApplicationFactory`. You
8989
access your application like a client application would:
@@ -97,11 +97,13 @@ public async Task OnTest()
9797
}
9898
```
9999

100-
Configuration
100+
### `Configuration`
101+
101102
This property grants you acces to the `IConfiguration` values that are
102103
currently available to the tested application.
103104

104-
Services
105+
### `Services`
106+
105107
This property grants you access to the DI service provider of the tested
106108
application.
107109

@@ -116,10 +118,12 @@ by the framework for each request.
116118
You can override the following methods to run code before and after each
117119
test:
118120

119-
InitializeAsync
121+
### `InitializeAsync`
122+
120123
Code executed before the execution of each test of the class.
121124

122-
DisposeAsync
125+
### `DisposeAsync`
126+
123127
Code executed after the execution of each test of the class.
124128

125129
## EntityFrameworkCore integration
@@ -129,6 +133,8 @@ integration by extending the
129133
`IntegrationTestBase<TEntryPoint, TContext>` class instead of the one
130134
that only uses the entrypoint.
131135

136+
### Configure database driver
137+
132138
You will need to override the abstract `ConfigureDbContext` method to
133139
tell the dependency injection library how to configure your context. A
134140
context instance will be generated per test and injected in your target
@@ -140,31 +146,38 @@ protected override void ConfigureDbContext(DbContextOptionsBuilder builder)
140146
=> builder.UseSqlite($"Data Source=test.sqlite");
141147
```
142148

149+
### Database lifetime strategy
150+
143151
The base class also exposes a `DatabaseTestStrategy` property that
144152
allows you to customize the test behavior regarding the database. You
145153
can write your own implementation which requires you to write specific
146154
code that will run before and after each test to set your database.
147155

148156
The library comes with 3 standard behaviors:
149157

150-
`IDatabaseTestStrategy<TContext>.Default`
158+
#### `IDatabaseTestStrategy<TContext>.Default`
159+
151160
By default the library simply instantates the context and disposes the
152161
instance after the test execution.
153162

154-
`IDatabaseTestStrategy<TContext>.Transaction`
163+
#### `IDatabaseTestStrategy<TContext>.Transaction`
164+
155165
This behavior will execute each test in a separate transaction. This can
156166
be used to prevent write operations to change the contents of the
157167
database. Obviously requires a database engine that supports
158168
transactions.
159169

160-
`IDatabaseTestStrategy<TContext>.DatabasePerTest`
170+
#### `IDatabaseTestStrategy<TContext>.DatabasePerTest`
171+
161172
This behavior creates a fresh database before test execution and drops
162173
it afterwards. It also applies migrations if any are found, otherwise it
163174
will use `EnsureCreated` (read [Create and Drop
164175
APIs](https://learn.microsoft.com/en-us/ef/core/managing-schemas/ensure-created)
165176
to understand how this might affect your test results). This allows test
166177
parallelization when transaction isolation is not sufficient or
167-
unavailable. You must combine this behavior with a random name
178+
unavailable.
179+
180+
You must combine this behavior with a random name
168181
interpolation in the connection string to run each test on it’s own
169182
database in parallel. Otherwise the tests will try to access the same
170183
database concurrently and will fail to drop it while other tests are
@@ -179,3 +192,49 @@ protected override void ConfigureDbContext(DbContextOptionsBuilder builder)
179192
```
180193

181194
This beahvior WILL drop your database after each test !
195+
196+
## OpenTelemetry integration
197+
198+
The library provides specific support for otel. You can achieve this
199+
integration by overriding the `OpenTelemetrySourceNames` property.
200+
All traces that match one of the provided source names will get caught
201+
in-memory and will be accessible through the `Activities` property.
202+
203+
You can use this feature to ensure that a specific branch has been called:
204+
205+
```cs
206+
public class OpenTelemetryTests(ITestOutputHelper output) : IntegrationTestBase<Program>(output)
207+
{
208+
protected override string[] OpenTelemetrySourceNames => ["SourceA"];
209+
210+
[Fact]
211+
public async Task Otel()
212+
{
213+
await Client.GetAsync("/api/otel");
214+
215+
// Check for activity existence
216+
Activities.Any(activity => activity.DisplayName == "return-null").Should().BeTrue();
217+
}
218+
}
219+
```
220+
221+
You can also use this feature to do performance tests:
222+
223+
```cs
224+
public class OpenTelemetryTests(ITestOutputHelper output) : IntegrationTestBase<Program>(output)
225+
{
226+
protected override string[] OpenTelemetrySourceNames => ["SourceA"];
227+
228+
private readonly TimeSpan limit = TimeSpan.FromMilliseconds(300);
229+
230+
[Fact]
231+
public async Task Otel()
232+
{
233+
await Client.GetAsync("/api/otel");
234+
Activities
235+
.Where(activity => activity.DisplayName == "database-insert")
236+
.Should().AllSatisfy(activity =>
237+
activity.Duration.Should().BeLessThan(limit));
238+
}
239+
}
240+
```

0 commit comments

Comments
 (0)