How to test DB.Configuration.AutoDetectChangesEnabled = false
I'm trying to write some tests for a class using NSubstitute.
Class constructor is:
public class ClassToTest : IClassToTest
{
private IDataBase DB;
public ClassToTest(IDatabase DB)
{
this.DB = DB;
this.DB.Configuration.AutoDetectChangesEnabled = false;
}
Here is my UnitTests class:
[TestFixture]
public class ClassToTestUnitTests
{
private ClassToTest _testClass;
[SetUp]
public void SetUp()
{
var Db = Substitute.For<IDatabase>();
//Db.Configuration.AutoDetectChangesEnabled = false; <- I've tried to do it like this
var dummyData = Substitute.For<DbSet<Data>, IQueryable<Data>, IDbAsyncEnumerable<Data>>().SetupData(GetData());
Db.Data.Returns(dummyData);
_testClass = new ClassToTest(Db);
}
Whenever I try to test some method, the test fails and there is a NullReferenceException and it goes in StackTrace to the SetUp method.
When I commented out the
this.DB.Configuration.AutoDetectChangesEnabled = false; in ClassToTest constructor the tests work fine.
Edit:
public interface IInventoryDatabase
{
DbSet<NamesV> NamesV { get; set; }
DbSet<Adress> Adresses { get; set; }
DbSet<RandomData> Randomdata { get; set; }
// (...more DbSets)
System.Data.Entity.Database Database { get; }
DbContextConfiguration Configuration { get; }
int SaveChanges();
}
c# unit-testing nsubstitute
add a comment |
I'm trying to write some tests for a class using NSubstitute.
Class constructor is:
public class ClassToTest : IClassToTest
{
private IDataBase DB;
public ClassToTest(IDatabase DB)
{
this.DB = DB;
this.DB.Configuration.AutoDetectChangesEnabled = false;
}
Here is my UnitTests class:
[TestFixture]
public class ClassToTestUnitTests
{
private ClassToTest _testClass;
[SetUp]
public void SetUp()
{
var Db = Substitute.For<IDatabase>();
//Db.Configuration.AutoDetectChangesEnabled = false; <- I've tried to do it like this
var dummyData = Substitute.For<DbSet<Data>, IQueryable<Data>, IDbAsyncEnumerable<Data>>().SetupData(GetData());
Db.Data.Returns(dummyData);
_testClass = new ClassToTest(Db);
}
Whenever I try to test some method, the test fails and there is a NullReferenceException and it goes in StackTrace to the SetUp method.
When I commented out the
this.DB.Configuration.AutoDetectChangesEnabled = false; in ClassToTest constructor the tests work fine.
Edit:
public interface IInventoryDatabase
{
DbSet<NamesV> NamesV { get; set; }
DbSet<Adress> Adresses { get; set; }
DbSet<RandomData> Randomdata { get; set; }
// (...more DbSets)
System.Data.Entity.Database Database { get; }
DbContextConfiguration Configuration { get; }
int SaveChanges();
}
c# unit-testing nsubstitute
What is the type ofDb.Configuration
? If it is not an interface or purely virtual class you may need to manually stub out that property:Db.Configuration.Returns(myConfiguration)
.
– David Tchepak
Nov 21 '18 at 22:21
@David Tchepak It's of type:System.Data.Entity.Infrastructure.DbContextConfiguration IDataBase.Configuration {get; }
Could you show me how that would look like?
– Alice
Nov 22 '18 at 8:12
From MSDN I can't see a public constructor for this type? In that case I do not think you will be able to stub theData
property. Can you share theIDatabase
definition?
– David Tchepak
Nov 22 '18 at 22:57
@David Tchepak yes, it seems that the lack of constructor is the problem. I've edited the code to show You IDatabase
– Alice
Nov 23 '18 at 13:39
add a comment |
I'm trying to write some tests for a class using NSubstitute.
Class constructor is:
public class ClassToTest : IClassToTest
{
private IDataBase DB;
public ClassToTest(IDatabase DB)
{
this.DB = DB;
this.DB.Configuration.AutoDetectChangesEnabled = false;
}
Here is my UnitTests class:
[TestFixture]
public class ClassToTestUnitTests
{
private ClassToTest _testClass;
[SetUp]
public void SetUp()
{
var Db = Substitute.For<IDatabase>();
//Db.Configuration.AutoDetectChangesEnabled = false; <- I've tried to do it like this
var dummyData = Substitute.For<DbSet<Data>, IQueryable<Data>, IDbAsyncEnumerable<Data>>().SetupData(GetData());
Db.Data.Returns(dummyData);
_testClass = new ClassToTest(Db);
}
Whenever I try to test some method, the test fails and there is a NullReferenceException and it goes in StackTrace to the SetUp method.
When I commented out the
this.DB.Configuration.AutoDetectChangesEnabled = false; in ClassToTest constructor the tests work fine.
Edit:
public interface IInventoryDatabase
{
DbSet<NamesV> NamesV { get; set; }
DbSet<Adress> Adresses { get; set; }
DbSet<RandomData> Randomdata { get; set; }
// (...more DbSets)
System.Data.Entity.Database Database { get; }
DbContextConfiguration Configuration { get; }
int SaveChanges();
}
c# unit-testing nsubstitute
I'm trying to write some tests for a class using NSubstitute.
Class constructor is:
public class ClassToTest : IClassToTest
{
private IDataBase DB;
public ClassToTest(IDatabase DB)
{
this.DB = DB;
this.DB.Configuration.AutoDetectChangesEnabled = false;
}
Here is my UnitTests class:
[TestFixture]
public class ClassToTestUnitTests
{
private ClassToTest _testClass;
[SetUp]
public void SetUp()
{
var Db = Substitute.For<IDatabase>();
//Db.Configuration.AutoDetectChangesEnabled = false; <- I've tried to do it like this
var dummyData = Substitute.For<DbSet<Data>, IQueryable<Data>, IDbAsyncEnumerable<Data>>().SetupData(GetData());
Db.Data.Returns(dummyData);
_testClass = new ClassToTest(Db);
}
Whenever I try to test some method, the test fails and there is a NullReferenceException and it goes in StackTrace to the SetUp method.
When I commented out the
this.DB.Configuration.AutoDetectChangesEnabled = false; in ClassToTest constructor the tests work fine.
Edit:
public interface IInventoryDatabase
{
DbSet<NamesV> NamesV { get; set; }
DbSet<Adress> Adresses { get; set; }
DbSet<RandomData> Randomdata { get; set; }
// (...more DbSets)
System.Data.Entity.Database Database { get; }
DbContextConfiguration Configuration { get; }
int SaveChanges();
}
c# unit-testing nsubstitute
c# unit-testing nsubstitute
edited Nov 23 '18 at 12:29
asked Nov 21 '18 at 15:16
Alice
347
347
What is the type ofDb.Configuration
? If it is not an interface or purely virtual class you may need to manually stub out that property:Db.Configuration.Returns(myConfiguration)
.
– David Tchepak
Nov 21 '18 at 22:21
@David Tchepak It's of type:System.Data.Entity.Infrastructure.DbContextConfiguration IDataBase.Configuration {get; }
Could you show me how that would look like?
– Alice
Nov 22 '18 at 8:12
From MSDN I can't see a public constructor for this type? In that case I do not think you will be able to stub theData
property. Can you share theIDatabase
definition?
– David Tchepak
Nov 22 '18 at 22:57
@David Tchepak yes, it seems that the lack of constructor is the problem. I've edited the code to show You IDatabase
– Alice
Nov 23 '18 at 13:39
add a comment |
What is the type ofDb.Configuration
? If it is not an interface or purely virtual class you may need to manually stub out that property:Db.Configuration.Returns(myConfiguration)
.
– David Tchepak
Nov 21 '18 at 22:21
@David Tchepak It's of type:System.Data.Entity.Infrastructure.DbContextConfiguration IDataBase.Configuration {get; }
Could you show me how that would look like?
– Alice
Nov 22 '18 at 8:12
From MSDN I can't see a public constructor for this type? In that case I do not think you will be able to stub theData
property. Can you share theIDatabase
definition?
– David Tchepak
Nov 22 '18 at 22:57
@David Tchepak yes, it seems that the lack of constructor is the problem. I've edited the code to show You IDatabase
– Alice
Nov 23 '18 at 13:39
What is the type of
Db.Configuration
? If it is not an interface or purely virtual class you may need to manually stub out that property: Db.Configuration.Returns(myConfiguration)
.– David Tchepak
Nov 21 '18 at 22:21
What is the type of
Db.Configuration
? If it is not an interface or purely virtual class you may need to manually stub out that property: Db.Configuration.Returns(myConfiguration)
.– David Tchepak
Nov 21 '18 at 22:21
@David Tchepak It's of type:
System.Data.Entity.Infrastructure.DbContextConfiguration IDataBase.Configuration {get; }
Could you show me how that would look like?– Alice
Nov 22 '18 at 8:12
@David Tchepak It's of type:
System.Data.Entity.Infrastructure.DbContextConfiguration IDataBase.Configuration {get; }
Could you show me how that would look like?– Alice
Nov 22 '18 at 8:12
From MSDN I can't see a public constructor for this type? In that case I do not think you will be able to stub the
Data
property. Can you share the IDatabase
definition?– David Tchepak
Nov 22 '18 at 22:57
From MSDN I can't see a public constructor for this type? In that case I do not think you will be able to stub the
Data
property. Can you share the IDatabase
definition?– David Tchepak
Nov 22 '18 at 22:57
@David Tchepak yes, it seems that the lack of constructor is the problem. I've edited the code to show You IDatabase
– Alice
Nov 23 '18 at 13:39
@David Tchepak yes, it seems that the lack of constructor is the problem. I've edited the code to show You IDatabase
– Alice
Nov 23 '18 at 13:39
add a comment |
1 Answer
1
active
oldest
votes
The reason for the NullReferenceException
is that NSubstitute cannot automatically substitute for DbContextConfiguration
(it can only do so for purely virtual classes).
Normally we could work around this by manually configuration this property, something like Db.Configuration.Returns(myConfiguration)
, but in this case DbContextConfiguration
does not seem to have a public constructor so we are unable to create an instance for myConfiguration
.
At this stage I can think of two main options: wrap the problematic class in a more testable adapter class; or switch to testing this at a different level. (My preference is the latter which I'll explain below.)
The first option involves something like this:
public interface IDbContextConfiguration {
bool AutoDetectChangesEnabled { get; set; }
// ... any other required members here ...
}
public class DbContextConfigurationAdapter : IDbContextConfiguration {
DbContextConfiguration config;
public DbContextConfigurationAdapter(DbContextConfiguration config) {
this.config = config;
}
public bool AutoDetectChangedEnabled {
get { return config.AutoDetectChangedEnabled; }
set { config = value; }
}
}
Then updating IInventoryDatabase
to using the more testable IDbContextConfiguration
type. My opposition to this approach is that it can end up requiring a lot of work for something that should be fairly simple. This approach can be very useful for cases where we have behaviours that make sense to be grouped under a logical interface, but for working with an AutoDetectChangedEnabled
property this seems unnecessary work.
The other option is to test this at a different level. I think the friction in testing the current code is that we are trying to substitute for details of Entity Framework, rather than interfaces we've created for partitioning the logical details of our app. Search for "don't mock types you don't own" for more information on why this can be a problem (I've written about it before here).
One example of testing at a different level is to switch to an in-memory database for testing this part of the code. This will tell you much more valuable information: given a known state of the test database, you are demonstrating the queries return the expected information. This is in contrast to a test showing we are calling Entity Framework in the way we think is required.
To combine this approach with mocking (not necessarily required!), we can create a higher level interface and substitute for that for testing our application code, then make an implementation of that interface and test that using the in-memory database. We have then divided the application into two parts that we can test independently: first that our app uses data from the data access interface correctly, and secondly that our implementation of that interface works as expected.
So that would give us something like this:
public interface IAppDatabase {
// These members just for example. Maybe instead of something general like
// `GetAllNames()` we have operations specific to app operations such as
// `UpdateAddress(Guid id, Address newAddress)`, `GetNameFor(SomeParams p)` etc.
Task<List<Name>> GetAllNames();
Task<Address> LookupAddress(Guid id);
}
public class AppDatabase : IAppDatabase {
// ...
public AppDatabase(IInventoryDatabase db) { ... }
public Task<List<Name>> GetAllNames() {
// use `db` and Entity Framework to retrieve data...
}
// ...
}
The AppDatabase
class we test with an in-memory database. The rest of the app we test with respect to a substitute IAppDatabase
.
Note that we can skip the mocking step here by using the in-memory database for all relevant tests. Using mocking may be easier than setting up all the required data in the database, or may make tests run faster. Or maybe not -- I suggest considering both options.
Hope this helps.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53415138%2fhow-to-test-db-configuration-autodetectchangesenabled-false%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
The reason for the NullReferenceException
is that NSubstitute cannot automatically substitute for DbContextConfiguration
(it can only do so for purely virtual classes).
Normally we could work around this by manually configuration this property, something like Db.Configuration.Returns(myConfiguration)
, but in this case DbContextConfiguration
does not seem to have a public constructor so we are unable to create an instance for myConfiguration
.
At this stage I can think of two main options: wrap the problematic class in a more testable adapter class; or switch to testing this at a different level. (My preference is the latter which I'll explain below.)
The first option involves something like this:
public interface IDbContextConfiguration {
bool AutoDetectChangesEnabled { get; set; }
// ... any other required members here ...
}
public class DbContextConfigurationAdapter : IDbContextConfiguration {
DbContextConfiguration config;
public DbContextConfigurationAdapter(DbContextConfiguration config) {
this.config = config;
}
public bool AutoDetectChangedEnabled {
get { return config.AutoDetectChangedEnabled; }
set { config = value; }
}
}
Then updating IInventoryDatabase
to using the more testable IDbContextConfiguration
type. My opposition to this approach is that it can end up requiring a lot of work for something that should be fairly simple. This approach can be very useful for cases where we have behaviours that make sense to be grouped under a logical interface, but for working with an AutoDetectChangedEnabled
property this seems unnecessary work.
The other option is to test this at a different level. I think the friction in testing the current code is that we are trying to substitute for details of Entity Framework, rather than interfaces we've created for partitioning the logical details of our app. Search for "don't mock types you don't own" for more information on why this can be a problem (I've written about it before here).
One example of testing at a different level is to switch to an in-memory database for testing this part of the code. This will tell you much more valuable information: given a known state of the test database, you are demonstrating the queries return the expected information. This is in contrast to a test showing we are calling Entity Framework in the way we think is required.
To combine this approach with mocking (not necessarily required!), we can create a higher level interface and substitute for that for testing our application code, then make an implementation of that interface and test that using the in-memory database. We have then divided the application into two parts that we can test independently: first that our app uses data from the data access interface correctly, and secondly that our implementation of that interface works as expected.
So that would give us something like this:
public interface IAppDatabase {
// These members just for example. Maybe instead of something general like
// `GetAllNames()` we have operations specific to app operations such as
// `UpdateAddress(Guid id, Address newAddress)`, `GetNameFor(SomeParams p)` etc.
Task<List<Name>> GetAllNames();
Task<Address> LookupAddress(Guid id);
}
public class AppDatabase : IAppDatabase {
// ...
public AppDatabase(IInventoryDatabase db) { ... }
public Task<List<Name>> GetAllNames() {
// use `db` and Entity Framework to retrieve data...
}
// ...
}
The AppDatabase
class we test with an in-memory database. The rest of the app we test with respect to a substitute IAppDatabase
.
Note that we can skip the mocking step here by using the in-memory database for all relevant tests. Using mocking may be easier than setting up all the required data in the database, or may make tests run faster. Or maybe not -- I suggest considering both options.
Hope this helps.
add a comment |
The reason for the NullReferenceException
is that NSubstitute cannot automatically substitute for DbContextConfiguration
(it can only do so for purely virtual classes).
Normally we could work around this by manually configuration this property, something like Db.Configuration.Returns(myConfiguration)
, but in this case DbContextConfiguration
does not seem to have a public constructor so we are unable to create an instance for myConfiguration
.
At this stage I can think of two main options: wrap the problematic class in a more testable adapter class; or switch to testing this at a different level. (My preference is the latter which I'll explain below.)
The first option involves something like this:
public interface IDbContextConfiguration {
bool AutoDetectChangesEnabled { get; set; }
// ... any other required members here ...
}
public class DbContextConfigurationAdapter : IDbContextConfiguration {
DbContextConfiguration config;
public DbContextConfigurationAdapter(DbContextConfiguration config) {
this.config = config;
}
public bool AutoDetectChangedEnabled {
get { return config.AutoDetectChangedEnabled; }
set { config = value; }
}
}
Then updating IInventoryDatabase
to using the more testable IDbContextConfiguration
type. My opposition to this approach is that it can end up requiring a lot of work for something that should be fairly simple. This approach can be very useful for cases where we have behaviours that make sense to be grouped under a logical interface, but for working with an AutoDetectChangedEnabled
property this seems unnecessary work.
The other option is to test this at a different level. I think the friction in testing the current code is that we are trying to substitute for details of Entity Framework, rather than interfaces we've created for partitioning the logical details of our app. Search for "don't mock types you don't own" for more information on why this can be a problem (I've written about it before here).
One example of testing at a different level is to switch to an in-memory database for testing this part of the code. This will tell you much more valuable information: given a known state of the test database, you are demonstrating the queries return the expected information. This is in contrast to a test showing we are calling Entity Framework in the way we think is required.
To combine this approach with mocking (not necessarily required!), we can create a higher level interface and substitute for that for testing our application code, then make an implementation of that interface and test that using the in-memory database. We have then divided the application into two parts that we can test independently: first that our app uses data from the data access interface correctly, and secondly that our implementation of that interface works as expected.
So that would give us something like this:
public interface IAppDatabase {
// These members just for example. Maybe instead of something general like
// `GetAllNames()` we have operations specific to app operations such as
// `UpdateAddress(Guid id, Address newAddress)`, `GetNameFor(SomeParams p)` etc.
Task<List<Name>> GetAllNames();
Task<Address> LookupAddress(Guid id);
}
public class AppDatabase : IAppDatabase {
// ...
public AppDatabase(IInventoryDatabase db) { ... }
public Task<List<Name>> GetAllNames() {
// use `db` and Entity Framework to retrieve data...
}
// ...
}
The AppDatabase
class we test with an in-memory database. The rest of the app we test with respect to a substitute IAppDatabase
.
Note that we can skip the mocking step here by using the in-memory database for all relevant tests. Using mocking may be easier than setting up all the required data in the database, or may make tests run faster. Or maybe not -- I suggest considering both options.
Hope this helps.
add a comment |
The reason for the NullReferenceException
is that NSubstitute cannot automatically substitute for DbContextConfiguration
(it can only do so for purely virtual classes).
Normally we could work around this by manually configuration this property, something like Db.Configuration.Returns(myConfiguration)
, but in this case DbContextConfiguration
does not seem to have a public constructor so we are unable to create an instance for myConfiguration
.
At this stage I can think of two main options: wrap the problematic class in a more testable adapter class; or switch to testing this at a different level. (My preference is the latter which I'll explain below.)
The first option involves something like this:
public interface IDbContextConfiguration {
bool AutoDetectChangesEnabled { get; set; }
// ... any other required members here ...
}
public class DbContextConfigurationAdapter : IDbContextConfiguration {
DbContextConfiguration config;
public DbContextConfigurationAdapter(DbContextConfiguration config) {
this.config = config;
}
public bool AutoDetectChangedEnabled {
get { return config.AutoDetectChangedEnabled; }
set { config = value; }
}
}
Then updating IInventoryDatabase
to using the more testable IDbContextConfiguration
type. My opposition to this approach is that it can end up requiring a lot of work for something that should be fairly simple. This approach can be very useful for cases where we have behaviours that make sense to be grouped under a logical interface, but for working with an AutoDetectChangedEnabled
property this seems unnecessary work.
The other option is to test this at a different level. I think the friction in testing the current code is that we are trying to substitute for details of Entity Framework, rather than interfaces we've created for partitioning the logical details of our app. Search for "don't mock types you don't own" for more information on why this can be a problem (I've written about it before here).
One example of testing at a different level is to switch to an in-memory database for testing this part of the code. This will tell you much more valuable information: given a known state of the test database, you are demonstrating the queries return the expected information. This is in contrast to a test showing we are calling Entity Framework in the way we think is required.
To combine this approach with mocking (not necessarily required!), we can create a higher level interface and substitute for that for testing our application code, then make an implementation of that interface and test that using the in-memory database. We have then divided the application into two parts that we can test independently: first that our app uses data from the data access interface correctly, and secondly that our implementation of that interface works as expected.
So that would give us something like this:
public interface IAppDatabase {
// These members just for example. Maybe instead of something general like
// `GetAllNames()` we have operations specific to app operations such as
// `UpdateAddress(Guid id, Address newAddress)`, `GetNameFor(SomeParams p)` etc.
Task<List<Name>> GetAllNames();
Task<Address> LookupAddress(Guid id);
}
public class AppDatabase : IAppDatabase {
// ...
public AppDatabase(IInventoryDatabase db) { ... }
public Task<List<Name>> GetAllNames() {
// use `db` and Entity Framework to retrieve data...
}
// ...
}
The AppDatabase
class we test with an in-memory database. The rest of the app we test with respect to a substitute IAppDatabase
.
Note that we can skip the mocking step here by using the in-memory database for all relevant tests. Using mocking may be easier than setting up all the required data in the database, or may make tests run faster. Or maybe not -- I suggest considering both options.
Hope this helps.
The reason for the NullReferenceException
is that NSubstitute cannot automatically substitute for DbContextConfiguration
(it can only do so for purely virtual classes).
Normally we could work around this by manually configuration this property, something like Db.Configuration.Returns(myConfiguration)
, but in this case DbContextConfiguration
does not seem to have a public constructor so we are unable to create an instance for myConfiguration
.
At this stage I can think of two main options: wrap the problematic class in a more testable adapter class; or switch to testing this at a different level. (My preference is the latter which I'll explain below.)
The first option involves something like this:
public interface IDbContextConfiguration {
bool AutoDetectChangesEnabled { get; set; }
// ... any other required members here ...
}
public class DbContextConfigurationAdapter : IDbContextConfiguration {
DbContextConfiguration config;
public DbContextConfigurationAdapter(DbContextConfiguration config) {
this.config = config;
}
public bool AutoDetectChangedEnabled {
get { return config.AutoDetectChangedEnabled; }
set { config = value; }
}
}
Then updating IInventoryDatabase
to using the more testable IDbContextConfiguration
type. My opposition to this approach is that it can end up requiring a lot of work for something that should be fairly simple. This approach can be very useful for cases where we have behaviours that make sense to be grouped under a logical interface, but for working with an AutoDetectChangedEnabled
property this seems unnecessary work.
The other option is to test this at a different level. I think the friction in testing the current code is that we are trying to substitute for details of Entity Framework, rather than interfaces we've created for partitioning the logical details of our app. Search for "don't mock types you don't own" for more information on why this can be a problem (I've written about it before here).
One example of testing at a different level is to switch to an in-memory database for testing this part of the code. This will tell you much more valuable information: given a known state of the test database, you are demonstrating the queries return the expected information. This is in contrast to a test showing we are calling Entity Framework in the way we think is required.
To combine this approach with mocking (not necessarily required!), we can create a higher level interface and substitute for that for testing our application code, then make an implementation of that interface and test that using the in-memory database. We have then divided the application into two parts that we can test independently: first that our app uses data from the data access interface correctly, and secondly that our implementation of that interface works as expected.
So that would give us something like this:
public interface IAppDatabase {
// These members just for example. Maybe instead of something general like
// `GetAllNames()` we have operations specific to app operations such as
// `UpdateAddress(Guid id, Address newAddress)`, `GetNameFor(SomeParams p)` etc.
Task<List<Name>> GetAllNames();
Task<Address> LookupAddress(Guid id);
}
public class AppDatabase : IAppDatabase {
// ...
public AppDatabase(IInventoryDatabase db) { ... }
public Task<List<Name>> GetAllNames() {
// use `db` and Entity Framework to retrieve data...
}
// ...
}
The AppDatabase
class we test with an in-memory database. The rest of the app we test with respect to a substitute IAppDatabase
.
Note that we can skip the mocking step here by using the in-memory database for all relevant tests. Using mocking may be easier than setting up all the required data in the database, or may make tests run faster. Or maybe not -- I suggest considering both options.
Hope this helps.
answered Nov 26 '18 at 0:17
David Tchepak
6,8123248
6,8123248
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53415138%2fhow-to-test-db-configuration-autodetectchangesenabled-false%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
What is the type of
Db.Configuration
? If it is not an interface or purely virtual class you may need to manually stub out that property:Db.Configuration.Returns(myConfiguration)
.– David Tchepak
Nov 21 '18 at 22:21
@David Tchepak It's of type:
System.Data.Entity.Infrastructure.DbContextConfiguration IDataBase.Configuration {get; }
Could you show me how that would look like?– Alice
Nov 22 '18 at 8:12
From MSDN I can't see a public constructor for this type? In that case I do not think you will be able to stub the
Data
property. Can you share theIDatabase
definition?– David Tchepak
Nov 22 '18 at 22:57
@David Tchepak yes, it seems that the lack of constructor is the problem. I've edited the code to show You IDatabase
– Alice
Nov 23 '18 at 13:39