Why is my ef core data context disposed before use in a service under test?












0














Background: I am writing tests around services that make use of ef core. I want to use sqllite as it is relational.



I have written a base class for tests that will use a mock db factory I wrote to setup basic generic things like http mocking and the DAL.



namespace Bll.UnitTests
{
public class TestBase : IDisposable
{
// pass httpclient as dependency, setup messageHandler for stubbing
protected HttpClient httpClient;
protected Mock<HttpMessageHandlerFake> fakeHttpMessageHandler = new Mock<HttpMessageHandlerFake> { CallBase = true };

protected Mock<Logger> loggerMock;
protected DalContext dataContext;

protected MockDbFactory mockDbFactory;

public TestBase()
{
mockDbFactory = new MockDbFactory();

httpClient = new HttpClient(fakeHttpMessageHandler.Object);
dataContext = mockDbFactory.testDb;
loggerMock = new Mock<Logger>(dataContext);
}

public void Dispose()
{
mockDbFactory.Dispose();
}
}
}


Here is my mock db factory that should just setup a connection in memory and seems to work.



using Dal;
using Microsoft.EntityFrameworkCore;
using Moq;
using Microsoft.Data.Sqlite;
using System;
using System.Collections.Generic;

namespace Bll.UnitTests.Factories
{
// In-memory database only exists while the connection is open
public class MockDbFactory : IDisposable
{
private SqliteConnection connection;
public DalContext testDb;

public MockDbFactory()
{
OpenConnection();
testDb = GetTestDb();
}

public void Dispose()
{
CloseConnection();
}

private void OpenConnection()
{
connection = new SqliteConnection("DataSource=:memory:");
connection.Open();
}

private void CloseConnection()
{
connection.Close();
}

private DalContext GetTestDb()
{
var options = new DbContextOptionsBuilder<DalContext>()
.UseSqlite(connection)
.Options;

// Create the schema in the database
using (var context = new DalContext(options))
{
context.Database.EnsureCreated();
return context;
}
}
}
}


In my test class datacontext is disposed when I debug my service under test.



public class LocationServiceTest : TestBase
{
private LocationService sut;

public LocationServiceTest(): base()
{
sut = new LocationService(
httpClient,
loggerMock.Object,
dataContext
);
}

[Fact]
public async Task UpdateCountriesAsync_CallsCountryApiAndUpdatesDatabase()
{
// arrange
// setup get country data to return 2 countries
var temp = BuildCountryApiReturnable(2);
fakeHttpMessageHandler.Setup(f => f.Send(It.IsAny<HttpRequestMessage>())).Returns(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(temp)
});

// act
try
{
var result = await sut.UpdateCountriesAsync();

// assert
Assert.True(dataContext.Country.Count() == 2);
Assert.True(dataContext.Location.Count() == 2);
}
catch(Exception e)
{
throw e;
}

}


I think I understand that a using statement is necessary as this will create my connection and dispose of it, but I am trying to do that manually so that I can inject the data context into my service. If I have to wrap everything in a using statement I will be forced to change my service..










share|improve this question






















  • Entity Framework Core provides the In-Memory Database exactly for testing. Don't try to mock EF Core, use it as it is intended
    – Camilo Terevinto
    Nov 12 '18 at 22:13










  • @CamiloTerevinto, OP not mocking EF Core, instead OP uses SQLLite provider with "in-memory' option, which is same as EF Core In Memory Database, but with relation database constraints.
    – Fabio
    Nov 13 '18 at 0:51










  • Remove using in GetTestDb method and make consumer class responsible for disposing created context. If so then CreateTestDb would be better name.
    – Fabio
    Nov 13 '18 at 1:24
















0














Background: I am writing tests around services that make use of ef core. I want to use sqllite as it is relational.



I have written a base class for tests that will use a mock db factory I wrote to setup basic generic things like http mocking and the DAL.



namespace Bll.UnitTests
{
public class TestBase : IDisposable
{
// pass httpclient as dependency, setup messageHandler for stubbing
protected HttpClient httpClient;
protected Mock<HttpMessageHandlerFake> fakeHttpMessageHandler = new Mock<HttpMessageHandlerFake> { CallBase = true };

protected Mock<Logger> loggerMock;
protected DalContext dataContext;

protected MockDbFactory mockDbFactory;

public TestBase()
{
mockDbFactory = new MockDbFactory();

httpClient = new HttpClient(fakeHttpMessageHandler.Object);
dataContext = mockDbFactory.testDb;
loggerMock = new Mock<Logger>(dataContext);
}

public void Dispose()
{
mockDbFactory.Dispose();
}
}
}


Here is my mock db factory that should just setup a connection in memory and seems to work.



using Dal;
using Microsoft.EntityFrameworkCore;
using Moq;
using Microsoft.Data.Sqlite;
using System;
using System.Collections.Generic;

namespace Bll.UnitTests.Factories
{
// In-memory database only exists while the connection is open
public class MockDbFactory : IDisposable
{
private SqliteConnection connection;
public DalContext testDb;

public MockDbFactory()
{
OpenConnection();
testDb = GetTestDb();
}

public void Dispose()
{
CloseConnection();
}

private void OpenConnection()
{
connection = new SqliteConnection("DataSource=:memory:");
connection.Open();
}

private void CloseConnection()
{
connection.Close();
}

private DalContext GetTestDb()
{
var options = new DbContextOptionsBuilder<DalContext>()
.UseSqlite(connection)
.Options;

// Create the schema in the database
using (var context = new DalContext(options))
{
context.Database.EnsureCreated();
return context;
}
}
}
}


In my test class datacontext is disposed when I debug my service under test.



public class LocationServiceTest : TestBase
{
private LocationService sut;

public LocationServiceTest(): base()
{
sut = new LocationService(
httpClient,
loggerMock.Object,
dataContext
);
}

[Fact]
public async Task UpdateCountriesAsync_CallsCountryApiAndUpdatesDatabase()
{
// arrange
// setup get country data to return 2 countries
var temp = BuildCountryApiReturnable(2);
fakeHttpMessageHandler.Setup(f => f.Send(It.IsAny<HttpRequestMessage>())).Returns(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(temp)
});

// act
try
{
var result = await sut.UpdateCountriesAsync();

// assert
Assert.True(dataContext.Country.Count() == 2);
Assert.True(dataContext.Location.Count() == 2);
}
catch(Exception e)
{
throw e;
}

}


I think I understand that a using statement is necessary as this will create my connection and dispose of it, but I am trying to do that manually so that I can inject the data context into my service. If I have to wrap everything in a using statement I will be forced to change my service..










share|improve this question






















  • Entity Framework Core provides the In-Memory Database exactly for testing. Don't try to mock EF Core, use it as it is intended
    – Camilo Terevinto
    Nov 12 '18 at 22:13










  • @CamiloTerevinto, OP not mocking EF Core, instead OP uses SQLLite provider with "in-memory' option, which is same as EF Core In Memory Database, but with relation database constraints.
    – Fabio
    Nov 13 '18 at 0:51










  • Remove using in GetTestDb method and make consumer class responsible for disposing created context. If so then CreateTestDb would be better name.
    – Fabio
    Nov 13 '18 at 1:24














0












0








0







Background: I am writing tests around services that make use of ef core. I want to use sqllite as it is relational.



I have written a base class for tests that will use a mock db factory I wrote to setup basic generic things like http mocking and the DAL.



namespace Bll.UnitTests
{
public class TestBase : IDisposable
{
// pass httpclient as dependency, setup messageHandler for stubbing
protected HttpClient httpClient;
protected Mock<HttpMessageHandlerFake> fakeHttpMessageHandler = new Mock<HttpMessageHandlerFake> { CallBase = true };

protected Mock<Logger> loggerMock;
protected DalContext dataContext;

protected MockDbFactory mockDbFactory;

public TestBase()
{
mockDbFactory = new MockDbFactory();

httpClient = new HttpClient(fakeHttpMessageHandler.Object);
dataContext = mockDbFactory.testDb;
loggerMock = new Mock<Logger>(dataContext);
}

public void Dispose()
{
mockDbFactory.Dispose();
}
}
}


Here is my mock db factory that should just setup a connection in memory and seems to work.



using Dal;
using Microsoft.EntityFrameworkCore;
using Moq;
using Microsoft.Data.Sqlite;
using System;
using System.Collections.Generic;

namespace Bll.UnitTests.Factories
{
// In-memory database only exists while the connection is open
public class MockDbFactory : IDisposable
{
private SqliteConnection connection;
public DalContext testDb;

public MockDbFactory()
{
OpenConnection();
testDb = GetTestDb();
}

public void Dispose()
{
CloseConnection();
}

private void OpenConnection()
{
connection = new SqliteConnection("DataSource=:memory:");
connection.Open();
}

private void CloseConnection()
{
connection.Close();
}

private DalContext GetTestDb()
{
var options = new DbContextOptionsBuilder<DalContext>()
.UseSqlite(connection)
.Options;

// Create the schema in the database
using (var context = new DalContext(options))
{
context.Database.EnsureCreated();
return context;
}
}
}
}


In my test class datacontext is disposed when I debug my service under test.



public class LocationServiceTest : TestBase
{
private LocationService sut;

public LocationServiceTest(): base()
{
sut = new LocationService(
httpClient,
loggerMock.Object,
dataContext
);
}

[Fact]
public async Task UpdateCountriesAsync_CallsCountryApiAndUpdatesDatabase()
{
// arrange
// setup get country data to return 2 countries
var temp = BuildCountryApiReturnable(2);
fakeHttpMessageHandler.Setup(f => f.Send(It.IsAny<HttpRequestMessage>())).Returns(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(temp)
});

// act
try
{
var result = await sut.UpdateCountriesAsync();

// assert
Assert.True(dataContext.Country.Count() == 2);
Assert.True(dataContext.Location.Count() == 2);
}
catch(Exception e)
{
throw e;
}

}


I think I understand that a using statement is necessary as this will create my connection and dispose of it, but I am trying to do that manually so that I can inject the data context into my service. If I have to wrap everything in a using statement I will be forced to change my service..










share|improve this question













Background: I am writing tests around services that make use of ef core. I want to use sqllite as it is relational.



I have written a base class for tests that will use a mock db factory I wrote to setup basic generic things like http mocking and the DAL.



namespace Bll.UnitTests
{
public class TestBase : IDisposable
{
// pass httpclient as dependency, setup messageHandler for stubbing
protected HttpClient httpClient;
protected Mock<HttpMessageHandlerFake> fakeHttpMessageHandler = new Mock<HttpMessageHandlerFake> { CallBase = true };

protected Mock<Logger> loggerMock;
protected DalContext dataContext;

protected MockDbFactory mockDbFactory;

public TestBase()
{
mockDbFactory = new MockDbFactory();

httpClient = new HttpClient(fakeHttpMessageHandler.Object);
dataContext = mockDbFactory.testDb;
loggerMock = new Mock<Logger>(dataContext);
}

public void Dispose()
{
mockDbFactory.Dispose();
}
}
}


Here is my mock db factory that should just setup a connection in memory and seems to work.



using Dal;
using Microsoft.EntityFrameworkCore;
using Moq;
using Microsoft.Data.Sqlite;
using System;
using System.Collections.Generic;

namespace Bll.UnitTests.Factories
{
// In-memory database only exists while the connection is open
public class MockDbFactory : IDisposable
{
private SqliteConnection connection;
public DalContext testDb;

public MockDbFactory()
{
OpenConnection();
testDb = GetTestDb();
}

public void Dispose()
{
CloseConnection();
}

private void OpenConnection()
{
connection = new SqliteConnection("DataSource=:memory:");
connection.Open();
}

private void CloseConnection()
{
connection.Close();
}

private DalContext GetTestDb()
{
var options = new DbContextOptionsBuilder<DalContext>()
.UseSqlite(connection)
.Options;

// Create the schema in the database
using (var context = new DalContext(options))
{
context.Database.EnsureCreated();
return context;
}
}
}
}


In my test class datacontext is disposed when I debug my service under test.



public class LocationServiceTest : TestBase
{
private LocationService sut;

public LocationServiceTest(): base()
{
sut = new LocationService(
httpClient,
loggerMock.Object,
dataContext
);
}

[Fact]
public async Task UpdateCountriesAsync_CallsCountryApiAndUpdatesDatabase()
{
// arrange
// setup get country data to return 2 countries
var temp = BuildCountryApiReturnable(2);
fakeHttpMessageHandler.Setup(f => f.Send(It.IsAny<HttpRequestMessage>())).Returns(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(temp)
});

// act
try
{
var result = await sut.UpdateCountriesAsync();

// assert
Assert.True(dataContext.Country.Count() == 2);
Assert.True(dataContext.Location.Count() == 2);
}
catch(Exception e)
{
throw e;
}

}


I think I understand that a using statement is necessary as this will create my connection and dispose of it, but I am trying to do that manually so that I can inject the data context into my service. If I have to wrap everything in a using statement I will be forced to change my service..







c# .net-core ef-core-2.0






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 12 '18 at 21:58









CraigCraig

167113




167113












  • Entity Framework Core provides the In-Memory Database exactly for testing. Don't try to mock EF Core, use it as it is intended
    – Camilo Terevinto
    Nov 12 '18 at 22:13










  • @CamiloTerevinto, OP not mocking EF Core, instead OP uses SQLLite provider with "in-memory' option, which is same as EF Core In Memory Database, but with relation database constraints.
    – Fabio
    Nov 13 '18 at 0:51










  • Remove using in GetTestDb method and make consumer class responsible for disposing created context. If so then CreateTestDb would be better name.
    – Fabio
    Nov 13 '18 at 1:24


















  • Entity Framework Core provides the In-Memory Database exactly for testing. Don't try to mock EF Core, use it as it is intended
    – Camilo Terevinto
    Nov 12 '18 at 22:13










  • @CamiloTerevinto, OP not mocking EF Core, instead OP uses SQLLite provider with "in-memory' option, which is same as EF Core In Memory Database, but with relation database constraints.
    – Fabio
    Nov 13 '18 at 0:51










  • Remove using in GetTestDb method and make consumer class responsible for disposing created context. If so then CreateTestDb would be better name.
    – Fabio
    Nov 13 '18 at 1:24
















Entity Framework Core provides the In-Memory Database exactly for testing. Don't try to mock EF Core, use it as it is intended
– Camilo Terevinto
Nov 12 '18 at 22:13




Entity Framework Core provides the In-Memory Database exactly for testing. Don't try to mock EF Core, use it as it is intended
– Camilo Terevinto
Nov 12 '18 at 22:13












@CamiloTerevinto, OP not mocking EF Core, instead OP uses SQLLite provider with "in-memory' option, which is same as EF Core In Memory Database, but with relation database constraints.
– Fabio
Nov 13 '18 at 0:51




@CamiloTerevinto, OP not mocking EF Core, instead OP uses SQLLite provider with "in-memory' option, which is same as EF Core In Memory Database, but with relation database constraints.
– Fabio
Nov 13 '18 at 0:51












Remove using in GetTestDb method and make consumer class responsible for disposing created context. If so then CreateTestDb would be better name.
– Fabio
Nov 13 '18 at 1:24




Remove using in GetTestDb method and make consumer class responsible for disposing created context. If so then CreateTestDb would be better name.
– Fabio
Nov 13 '18 at 1:24












1 Answer
1






active

oldest

votes


















1














To answer your question:
In your MockDbFactory, you already disposed the context by the using clause:



private DalContext GetTestDb()
{
var options = new DbContextOptionsBuilder<DalContext>()
.UseSqlite(connection)
.Options;

// Create the schema in the database
using (var context = new DalContext(options))
{
context.Database.EnsureCreated();
return context; // context will already be disposed after returning
}
}


You should initiate a new instance of DalContext and handle its disposal in your MockDbFactory.Dispose method instead:



private DalContext GetTestDb()
{
...
testDb = new DalContext(options);
//Other configurations
}
...
public void Dispose()
{
CloseConnection();
testDb.Dispose();
}





share|improve this answer





















  • I am so dumb sometimes. Thanks so much
    – Craig
    Nov 13 '18 at 9:13











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
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53270706%2fwhy-is-my-ef-core-data-context-disposed-before-use-in-a-service-under-test%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









1














To answer your question:
In your MockDbFactory, you already disposed the context by the using clause:



private DalContext GetTestDb()
{
var options = new DbContextOptionsBuilder<DalContext>()
.UseSqlite(connection)
.Options;

// Create the schema in the database
using (var context = new DalContext(options))
{
context.Database.EnsureCreated();
return context; // context will already be disposed after returning
}
}


You should initiate a new instance of DalContext and handle its disposal in your MockDbFactory.Dispose method instead:



private DalContext GetTestDb()
{
...
testDb = new DalContext(options);
//Other configurations
}
...
public void Dispose()
{
CloseConnection();
testDb.Dispose();
}





share|improve this answer





















  • I am so dumb sometimes. Thanks so much
    – Craig
    Nov 13 '18 at 9:13
















1














To answer your question:
In your MockDbFactory, you already disposed the context by the using clause:



private DalContext GetTestDb()
{
var options = new DbContextOptionsBuilder<DalContext>()
.UseSqlite(connection)
.Options;

// Create the schema in the database
using (var context = new DalContext(options))
{
context.Database.EnsureCreated();
return context; // context will already be disposed after returning
}
}


You should initiate a new instance of DalContext and handle its disposal in your MockDbFactory.Dispose method instead:



private DalContext GetTestDb()
{
...
testDb = new DalContext(options);
//Other configurations
}
...
public void Dispose()
{
CloseConnection();
testDb.Dispose();
}





share|improve this answer





















  • I am so dumb sometimes. Thanks so much
    – Craig
    Nov 13 '18 at 9:13














1












1








1






To answer your question:
In your MockDbFactory, you already disposed the context by the using clause:



private DalContext GetTestDb()
{
var options = new DbContextOptionsBuilder<DalContext>()
.UseSqlite(connection)
.Options;

// Create the schema in the database
using (var context = new DalContext(options))
{
context.Database.EnsureCreated();
return context; // context will already be disposed after returning
}
}


You should initiate a new instance of DalContext and handle its disposal in your MockDbFactory.Dispose method instead:



private DalContext GetTestDb()
{
...
testDb = new DalContext(options);
//Other configurations
}
...
public void Dispose()
{
CloseConnection();
testDb.Dispose();
}





share|improve this answer












To answer your question:
In your MockDbFactory, you already disposed the context by the using clause:



private DalContext GetTestDb()
{
var options = new DbContextOptionsBuilder<DalContext>()
.UseSqlite(connection)
.Options;

// Create the schema in the database
using (var context = new DalContext(options))
{
context.Database.EnsureCreated();
return context; // context will already be disposed after returning
}
}


You should initiate a new instance of DalContext and handle its disposal in your MockDbFactory.Dispose method instead:



private DalContext GetTestDb()
{
...
testDb = new DalContext(options);
//Other configurations
}
...
public void Dispose()
{
CloseConnection();
testDb.Dispose();
}






share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 12 '18 at 22:25









LowkeyLowkey

512311




512311












  • I am so dumb sometimes. Thanks so much
    – Craig
    Nov 13 '18 at 9:13


















  • I am so dumb sometimes. Thanks so much
    – Craig
    Nov 13 '18 at 9:13
















I am so dumb sometimes. Thanks so much
– Craig
Nov 13 '18 at 9:13




I am so dumb sometimes. Thanks so much
– Craig
Nov 13 '18 at 9:13


















draft saved

draft discarded




















































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.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53270706%2fwhy-is-my-ef-core-data-context-disposed-before-use-in-a-service-under-test%23new-answer', 'question_page');
}
);

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







這個網誌中的熱門文章

Xamarin.form Move up view when keyboard appear

Post-Redirect-Get with Spring WebFlux and Thymeleaf

Anylogic : not able to use stopDelay()