@@ -7,16 +7,19 @@ for details on how this library works.
77
88## Definitions
99
10- ** Tested application**
10+ ### Tested application
11+
1112A dotnet application that you want to test. Also known as the * system
1213under test* (SUT).
1314
14- ** Entrypoint**
15+ ### Entrypoint
16+
1517A specific class of the tested application that is run when the
1618application start. For top-level statement applications this is the
1719` Program ` class.
1820
19- ** Test project**
21+ ### Test project
22+
2023A XUnit test project that implements tests and ensures that the tested
2124application behaves as expected.
2225
@@ -26,9 +29,8 @@ Simply extend the `IntegrationTestBase<TEntryPoint>` class and provide
2629the 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>
3739You can override the following methods to customize the tested
3840application:
3941
40- ConfigureAppConfiguration
42+ ### ` ConfigureAppConfiguration `
43+
4144Change the sources for the app configuration. By default, overrides the
4245application configuration sources with the following (lower overrides
4346higher):
@@ -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+
5155Change the app logging configuration. By default, redirects all logs
5256(all namespaces and all levels) to the XUnit output helper. If the test
5357fails, you get all the tested application logs in the test output.
5458
55- ConfigureAppServices
59+ ### ` ConfigureAppServices `
60+
5661Override dependency injection services of the tested application.
5762
5863If your test code and the tested application need to access the same
@@ -69,21 +74,16 @@ protected override void ConfigureAppServices(IServiceCollection services)
6974[Fact ]
7075public 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+
8787You can access the tested application using the ` Client ` property which
8888returns a pseudo ` HttpClient ` created by ` WebApplicationFactory ` . You
8989access your application like a client application would:
@@ -97,11 +97,13 @@ public async Task OnTest()
9797}
9898```
9999
100- Configuration
100+ ### ` Configuration `
101+
101102This property grants you acces to the ` IConfiguration ` values that are
102103currently available to the tested application.
103104
104- Services
105+ ### ` Services `
106+
105107This property grants you access to the DI service provider of the tested
106108application.
107109
@@ -116,10 +118,12 @@ by the framework for each request.
116118You can override the following methods to run code before and after each
117119test:
118120
119- InitializeAsync
121+ ### ` InitializeAsync `
122+
120123Code executed before the execution of each test of the class.
121124
122- DisposeAsync
125+ ### ` DisposeAsync `
126+
123127Code 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
130134that only uses the entrypoint.
131135
136+ ### Configure database driver
137+
132138You will need to override the abstract ` ConfigureDbContext ` method to
133139tell the dependency injection library how to configure your context. A
134140context 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+
143151The base class also exposes a ` DatabaseTestStrategy ` property that
144152allows you to customize the test behavior regarding the database. You
145153can write your own implementation which requires you to write specific
146154code that will run before and after each test to set your database.
147155
148156The library comes with 3 standard behaviors:
149157
150- ` IDatabaseTestStrategy<TContext>.Default `
158+ #### ` IDatabaseTestStrategy<TContext>.Default `
159+
151160By default the library simply instantates the context and disposes the
152161instance after the test execution.
153162
154- ` IDatabaseTestStrategy<TContext>.Transaction `
163+ #### ` IDatabaseTestStrategy<TContext>.Transaction `
164+
155165This behavior will execute each test in a separate transaction. This can
156166be used to prevent write operations to change the contents of the
157167database. Obviously requires a database engine that supports
158168transactions.
159169
160- ` IDatabaseTestStrategy<TContext>.DatabasePerTest `
170+ #### ` IDatabaseTestStrategy<TContext>.DatabasePerTest `
171+
161172This behavior creates a fresh database before test execution and drops
162173it afterwards. It also applies migrations if any are found, otherwise it
163174will use ` EnsureCreated ` (read [ Create and Drop
164175APIs] ( https://learn.microsoft.com/en-us/ef/core/managing-schemas/ensure-created )
165176to understand how this might affect your test results). This allows test
166177parallelization 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
168181interpolation in the connection string to run each test on it’s own
169182database in parallel. Otherwise the tests will try to access the same
170183database concurrently and will fail to drop it while other tests are
@@ -179,3 +192,49 @@ protected override void ConfigureDbContext(DbContextOptionsBuilder builder)
179192```
180193
181194This 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