Skip to content

Commit 896abbf

Browse files
committed
Testing: context factory may return null. added provider factory for creation of derived providers.
1 parent 6989347 commit 896abbf

File tree

6 files changed

+77
-43
lines changed

6 files changed

+77
-43
lines changed

src/Thinktecture.EntityFrameworkCore.SqlServer.Testing/EntityFrameworkCore/Testing/SqlServerTestDbContextProvider.cs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public class SqlServerTestDbContextProvider<T> : ITestDbContextProvider<T>
2525
private readonly IMigrationExecutionStrategy _migrationExecutionStrategy;
2626
private readonly DbConnection _masterConnection;
2727
private readonly IReadOnlyList<Action<T>> _contextInitializations;
28-
private readonly Func<DbContextOptions<T>, IDbDefaultSchema, T>? _contextFactory;
28+
private readonly Func<DbContextOptions<T>, IDbDefaultSchema, T?>? _contextFactory;
2929
private readonly TestingLoggingOptions _testingLoggingOptions;
3030

3131
private T? _arrangeDbContext;
@@ -152,10 +152,12 @@ public T CreateDbContext(bool useMasterConnection)
152152
/// <returns>A new instance of the database context.</returns>
153153
protected virtual T CreateDbContext(DbContextOptions<T> options, IDbDefaultSchema schema)
154154
{
155-
if (_contextFactory is not null)
156-
return _contextFactory(options, schema) ?? throw new Exception("The provided context factory must not return 'null'.");
155+
var ctx = _contextFactory?.Invoke(options, schema);
157156

158-
var ctx = Activator.CreateInstance(typeof(T), options, schema);
157+
if (ctx is not null)
158+
return ctx;
159+
160+
ctx = (T?)Activator.CreateInstance(typeof(T), options, schema);
159161

160162
if (ctx is null)
161163
{
@@ -165,12 +167,12 @@ protected virtual T CreateDbContext(DbContextOptions<T> options, IDbDefaultSchem
165167
Please provide the corresponding constructor or a custom factory via '{typeof(SqlServerTestDbContextProviderBuilder<T>).ShortDisplayName()}.{nameof(SqlServerTestDbContextProviderBuilder<T>.UseContextFactory)}'.");
166168
}
167169

168-
ctx = Activator.CreateInstance(typeof(T), options)
169-
?? throw new Exception(@$"Could not create an instance of type of '{typeof(T).ShortDisplayName()}' neither using constructor parameters ({typeof(DbContextOptions<T>).ShortDisplayName()} options, {nameof(IDbDefaultSchema)} schema) nor using construct ({typeof(DbContextOptions<T>).ShortDisplayName()} options).
170-
Please provide the corresponding constructor or a custom factory via '{typeof(SqlServerTestDbContextProviderBuilder<T>).ShortDisplayName()}.{nameof(SqlServerTestDbContextProviderBuilder<T>.UseContextFactory)}'.");
170+
ctx = (T)(Activator.CreateInstance(typeof(T), options)
171+
?? throw new Exception(@$"Could not create an instance of type of '{typeof(T).ShortDisplayName()}' neither using constructor parameters ({typeof(DbContextOptions<T>).ShortDisplayName()} options, {nameof(IDbDefaultSchema)} schema) nor using construct ({typeof(DbContextOptions<T>).ShortDisplayName()} options).
172+
Please provide the corresponding constructor or a custom factory via '{typeof(SqlServerTestDbContextProviderBuilder<T>).ShortDisplayName()}.{nameof(SqlServerTestDbContextProviderBuilder<T>.UseContextFactory)}'."));
171173
}
172174

173-
return (T)ctx;
175+
return ctx;
174176
}
175177

176178
/// <summary>

src/Thinktecture.EntityFrameworkCore.SqlServer.Testing/EntityFrameworkCore/Testing/SqlServerTestDbContextProviderBuilder.cs

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ public class SqlServerTestDbContextProviderBuilder<T> : TestDbContextProviderBui
2525

2626
private bool _useThinktectureSqlServerMigrationsSqlGenerator = true;
2727
private string? _sharedTablesSchema;
28-
private Func<DbContextOptions<T>, IDbDefaultSchema, T>? _contextFactory;
28+
private Func<DbContextOptions<T>, IDbDefaultSchema, T?>? _contextFactory;
29+
private Func<SqlServerTestDbContextProviderOptions<T>, SqlServerTestDbContextProvider<T>?>? _providerFactory;
2930

3031
/// <summary>
3132
/// Initializes new instance of <see cref="SqlServerTestDbContextProviderBuilder{T}"/>.
@@ -195,13 +196,25 @@ public SqlServerTestDbContextProviderBuilder<T> InitializeContext(Action<T> init
195196
/// </summary>
196197
/// <param name="contextFactory">Factory to create the context of type <typeparamref name="T"/>.</param>
197198
/// <returns>Current builder for chaining.</returns>
198-
public SqlServerTestDbContextProviderBuilder<T> UseContextFactory(Func<DbContextOptions<T>, IDbDefaultSchema, T>? contextFactory)
199+
public SqlServerTestDbContextProviderBuilder<T> UseContextFactory(Func<DbContextOptions<T>, IDbDefaultSchema, T?>? contextFactory)
199200
{
200201
_contextFactory = contextFactory;
201202

202203
return this;
203204
}
204205

206+
/// <summary>
207+
/// Delegates the creation of <see cref="SqlServerTestDbContextProvider{T}"/> to the provided <paramref name="providerFactory"/>.
208+
/// </summary>
209+
/// <param name="providerFactory">Factory to use for creation of <see cref="SqlServerTestDbContextProvider{T}"/>.</param>
210+
/// <returns>Current builder for chaining.</returns>
211+
public SqlServerTestDbContextProviderBuilder<T> UseProviderFactory(Func<SqlServerTestDbContextProviderOptions<T>, SqlServerTestDbContextProvider<T>?>? providerFactory)
212+
{
213+
_providerFactory = providerFactory;
214+
215+
return this;
216+
}
217+
205218
/// <summary>
206219
/// Gets/generates schema to be used.
207220
/// </summary>
@@ -296,18 +309,20 @@ public SqlServerTestDbContextProvider<T> Build()
296309
var masterDbContextOptions = CreateOptionsBuilder(state, masterConnection, schema).Options;
297310
var dbContextOptions = CreateOptionsBuilder(state, null, schema).Options;
298311

299-
return new SqlServerTestDbContextProvider<T>(new SqlServerTestDbContextProviderOptions<T>(masterConnection,
300-
state.MigrationExecutionStrategy ?? IMigrationExecutionStrategy.Migrations,
301-
masterDbContextOptions,
302-
dbContextOptions,
303-
loggingOptions,
304-
_ctxInitializations.ToList(),
305-
schema)
306-
{
307-
IsUsingSharedTables = _useSharedTables,
308-
ContextFactory = _contextFactory,
309-
ExecutedCommands = state.CommandCapturingInterceptor?.Commands
310-
});
312+
var options = new SqlServerTestDbContextProviderOptions<T>(masterConnection,
313+
state.MigrationExecutionStrategy ?? IMigrationExecutionStrategy.Migrations,
314+
masterDbContextOptions,
315+
dbContextOptions,
316+
loggingOptions,
317+
_ctxInitializations.ToList(),
318+
schema)
319+
{
320+
IsUsingSharedTables = _useSharedTables,
321+
ContextFactory = _contextFactory,
322+
ExecutedCommands = state.CommandCapturingInterceptor?.Commands
323+
};
324+
325+
return _providerFactory?.Invoke(options) ?? new SqlServerTestDbContextProvider<T>(options);
311326
}
312327
catch
313328
{

src/Thinktecture.EntityFrameworkCore.SqlServer.Testing/EntityFrameworkCore/Testing/SqlServerTestDbContextProviderOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public class SqlServerTestDbContextProviderOptions<T> : TestDbContextProviderOpt
2525
/// <summary>
2626
/// A factory method for creation of contexts of type <typeparamref name="T"/>.
2727
/// </summary>
28-
public Func<DbContextOptions<T>, IDbDefaultSchema, T>? ContextFactory { get; set; }
28+
public Func<DbContextOptions<T>, IDbDefaultSchema, T?>? ContextFactory { get; set; }
2929

3030
/// <summary>
3131
/// Isolation level to be used with shared tables.

src/Thinktecture.EntityFrameworkCore.Sqlite.Testing/EntityFrameworkCore/Testing/SqlServerTestDbContextProviderOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public class SqliteTestDbContextProviderOptions<T> : TestDbContextProviderOption
1313
/// <summary>
1414
/// A factory method for creation of contexts of type <typeparamref name="T"/>.
1515
/// </summary>
16-
public Func<DbContextOptions<T>, T>? ContextFactory { get; set; }
16+
public Func<DbContextOptions<T>, T?>? ContextFactory { get; set; }
1717

1818
/// <summary>
1919
/// The connection string.

src/Thinktecture.EntityFrameworkCore.Sqlite.Testing/EntityFrameworkCore/Testing/SqliteTestDbContextProvider.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public class SqliteTestDbContextProvider<T> : ITestDbContextProvider<T>
1919
private readonly IMigrationExecutionStrategy _migrationExecutionStrategy;
2020
private readonly DbConnection _masterConnection;
2121
private readonly IReadOnlyList<Action<T>> _contextInitializations;
22-
private readonly Func<DbContextOptions<T>, T>? _contextFactory;
22+
private readonly Func<DbContextOptions<T>, T?>? _contextFactory;
2323

2424
private T? _arrangeDbContext;
2525
private T? _actDbContext;
@@ -111,14 +111,16 @@ public T CreateDbContext(bool useMasterConnection)
111111
/// <returns>A new instance of the database context.</returns>
112112
protected virtual T CreateDbContext(DbContextOptions<T> options)
113113
{
114-
if (_contextFactory is not null)
115-
return _contextFactory(options) ?? throw new Exception("The provided context factory must not return 'null'.");
114+
var ctx = _contextFactory?.Invoke(options);
116115

117-
var ctx = Activator.CreateInstance(typeof(T), options)
116+
if (ctx is not null)
117+
return ctx;
118+
119+
ctx = (T)(Activator.CreateInstance(typeof(T), options)
118120
?? throw new Exception(@$"Could not create an instance of type of '{typeof(T).ShortDisplayName()}' using constructor parameters ({typeof(DbContextOptions<T>).ShortDisplayName()} options).
119-
Please provide the corresponding constructor or a custom factory via '{typeof(SqliteTestDbContextProviderBuilder<T>).ShortDisplayName()}.{nameof(SqliteTestDbContextProviderBuilder<T>.UseContextFactory)}'.");
121+
Please provide the corresponding constructor or a custom factory via '{typeof(SqliteTestDbContextProviderBuilder<T>).ShortDisplayName()}.{nameof(SqliteTestDbContextProviderBuilder<T>.UseContextFactory)}'."));
120122

121-
return (T)ctx;
123+
return ctx;
122124
}
123125

124126
/// <summary>

src/Thinktecture.EntityFrameworkCore.Sqlite.Testing/EntityFrameworkCore/Testing/SqliteTestDbContextProviderBuilder.cs

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ public class SqliteTestDbContextProviderBuilder<T> : TestDbContextProviderBuilde
1717
private readonly List<Action<SqliteDbContextOptionsBuilder>> _configuresSqliteOptionsCollection;
1818
private readonly List<Action<T>> _ctxInitializations;
1919

20-
private Func<DbContextOptions<T>, T>? _contextFactory;
20+
private Func<DbContextOptions<T>, T?>? _contextFactory;
21+
private Func<SqliteTestDbContextProviderOptions<T>, SqliteTestDbContextProvider<T>?>? _providerFactory;
2122

2223
/// <summary>
2324
/// Initializes new instance of <see cref="SqliteTestDbContextProviderBuilder{T}"/>.
@@ -155,13 +156,25 @@ public SqliteTestDbContextProviderBuilder<T> InitializeContext(Action<T> initial
155156
/// </summary>
156157
/// <param name="contextFactory">Factory to create the context of type <typeparamref name="T"/>.</param>
157158
/// <returns>Current builder for chaining.</returns>
158-
public SqliteTestDbContextProviderBuilder<T> UseContextFactory(Func<DbContextOptions<T>, T>? contextFactory)
159+
public SqliteTestDbContextProviderBuilder<T> UseContextFactory(Func<DbContextOptions<T>, T?>? contextFactory)
159160
{
160161
_contextFactory = contextFactory;
161162

162163
return this;
163164
}
164165

166+
/// <summary>
167+
/// Delegates the creation of <see cref="SqliteTestDbContextProvider{T}"/> to the provided <paramref name="providerFactory"/>.
168+
/// </summary>
169+
/// <param name="providerFactory">Factory to use for creation of <see cref="SqliteTestDbContextProvider{T}"/>.</param>
170+
/// <returns>Current builder for chaining.</returns>
171+
public SqliteTestDbContextProviderBuilder<T> UseProviderFactory(Func<SqliteTestDbContextProviderOptions<T>, SqliteTestDbContextProvider<T>?>? providerFactory)
172+
{
173+
_providerFactory = providerFactory;
174+
175+
return this;
176+
}
177+
165178
/// <summary>
166179
/// Creates and configures the <see cref="DbContextOptionsBuilder{TContext}"/>
167180
/// </summary>
@@ -238,17 +251,19 @@ public SqliteTestDbContextProvider<T> Build()
238251
var masterDbContextOptions = CreateOptionsBuilder(state, masterConnection, connectionString).Options;
239252
var dbContextOptions = CreateOptionsBuilder(state, null, connectionString).Options;
240253

241-
return new SqliteTestDbContextProvider<T>(new SqliteTestDbContextProviderOptions<T>(masterConnection,
242-
state.MigrationExecutionStrategy ?? IMigrationExecutionStrategy.Migrations,
243-
masterDbContextOptions,
244-
dbContextOptions,
245-
loggingOptions,
246-
_ctxInitializations.ToList(),
247-
connectionString)
248-
{
249-
ContextFactory = _contextFactory,
250-
ExecutedCommands = state.CommandCapturingInterceptor?.Commands
251-
});
254+
var options = new SqliteTestDbContextProviderOptions<T>(masterConnection,
255+
state.MigrationExecutionStrategy ?? IMigrationExecutionStrategy.Migrations,
256+
masterDbContextOptions,
257+
dbContextOptions,
258+
loggingOptions,
259+
_ctxInitializations.ToList(),
260+
connectionString)
261+
{
262+
ContextFactory = _contextFactory,
263+
ExecutedCommands = state.CommandCapturingInterceptor?.Commands
264+
};
265+
266+
return _providerFactory?.Invoke(options) ?? new SqliteTestDbContextProvider<T>(options);
252267
}
253268
catch
254269
{

0 commit comments

Comments
 (0)