Entity framework code first unit tests that require empty database - c#

I have a code that uses EF code first that I want to Unit tests in my unit test I want a real empty database in the start of the test so I did:
[TestInitialize]
public void Initialize()
{
Database.SetInitializer(new DropCreateDatabaseAlways<MyContext>());
}
[TestCleanup]
public void CleanUp()
{
MyContext db = new MyContext();
db.Database.Delete();
}
but because the tests run in parallel this is not work so I did a order test with my tests and it also
has issues because the database sometimes is not dropped because is in use...
Someone have better strategy? I thought maybe each test will create its own database ? if it is good idea how can I achieve this?

Please try this
[TestClass]
public class UnitTestClass
{
private static string testConnString;
[TestInitialize]
public void Initialize()
{
testConnString = GetTestConnString();
using (MyContext db = new MyContext(testConnString, new DropCreateDatabaseAlways<MyContext>()))
{
db.UnderlyingContext.Connection.Open();
}
}
[TestMethod]
public void TestMethod1()
{
}
[TestCleanup]
public void CleanUp()
{
using (MyContext db = new MyContext(testConnString))
{
db.Database.Delete();
}
}
private static string GetTestConnString()
{
SqlConnectionStringBuilder csb = new SqlConnectionStringBuilder();
csb.DataSource = #"MYPC\SQLEXPRESS"; // Replace it with your SQL-server name
csb.InitialCatalog = "DB"+Guid.NewGuid().ToString().Replace("-","");
csb.IntegratedSecurity = true;
return csb.ToString();
}
}
public class MyContext : DbContext
{
private static IDatabaseInitializer<MyContext> _Initializer;
public MyContext(string connString, IDatabaseInitializer<MyContext> initializer = null)
: base(connString)
{
_Initializer = initializer;
}
public ObjectContext UnderlyingContext
{
get { return (this as IObjectContextAdapter).ObjectContext; }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
if (_Initializer != null)
{
Database.SetInitializer(_Initializer);
}
base.OnModelCreating(modelBuilder);
}
}

What does "real" mean? Have you considered using an in-memory DB in your unit tests? With an in-memory DB like SQLite you can set up a fresh DB for each test with relatively little overhead. You can also prepare a test database once, store it to a file, and load it for each test. Check out this answer. And this link. You'll find more if you Google a little.
I would try to avoid relying on an ordering. The tests should be independent from each other to allow for clear traceability from failed tests to issues in the code. A test should not fail only because another test manipulated shared data.
Another concern for me would be performance. With a mandatory ordering parallel test execution is out of the question. And if you use a production-like DB setting for all your tests, they will definitely be much slower than with an in-memory replacement.

Related

Entity Framework Integration tests failing running multiple tests that are singularly passing [Resharper, NUnit, EF6]

I'm having an inconsistent behavior running Integration Test using Resharper 8.2, NUnit 2.6.4.
Depending one how many test I select, sometime all passes and sometime just firsts and lasts.
If instead I run each test singularly they all passes.
In this prototype I have use a base test class that wipe the database using an existing stored procedure (avoiding this step the result doesn't change) and then initialize the data.
Below the Class used to seed the database that is based on Builders and Entities.
public class DefaultTestData<TB, TE> : ITestData where TB:BaseBuilder<TB, TE>
{
public void Seed(DbContext context)
{
context.Set(typeof (TE)).Add(((TB) Activator.CreateInstance(typeof (TB))).Build());
context.Set(typeof (TE)).Add(((TB) Activator.CreateInstance(typeof (TB))).Build());
context.SaveChanges();
}
}
Base test Class, inherited by all test class.
[TestFixture]
public abstract class BaseTest
{
protected FmsDbContext Context = null;
public abstract ITestData InitializeData();
[Test]
public abstract void Mapping();
[Test]
public abstract void Delete();
[SetUp]
public virtual void SetupInitialData()
{
var data = InitializeData();
Context = new FmsDbContext();
// Context.Database.Initialize(true); -- Using initialize One or Zero test runs
if (data != null)
{
Database.SetInitializer(new TestDataInitializer(data));
}
}
[TearDown]
public virtual void Teardown()
{
if (Context != null)
{
Context.Dispose();
}
}
}
The custome Database Initializer Class
public class TestDataInitializer : IDatabaseInitializer<FmsDbContext>
{
private readonly ITestData _data;
public TestDataInitializer(ITestData data)
{
_data = data;
}
private void Seed(DbContext context)
{
if(_data != null)
_data.Seed(context);
}
public void InitializeDatabase(FmsDbContext context)
{
context.Database.ExecuteSqlCommand("EXEC [dbo].[uspWipeDatabase]");
Seed(context);
}
}
public interface ITestData
{
void Seed(DbContext context);
}
Simple test
[TestFixture]
public class TagTest : BaseTest
{
public override ITestData InitializeData()
{
return new DefaultTestData<TagBuilder, Tag>();
}
[Test]
public override void Mapping()
{
var tag = Context.Tags.FirstOrDefault();
Assert.NotNull(tag);
}
[Test]
public override void Delete()
{
var initialCount = Context.Tags.Count();
var tag = Context.Tags.FirstOrDefault();
Context.Tags.Remove(tag);
Context.SaveChanges();
Assert.AreEqual(Context.Tags.Count(), initialCount - 1);
}
}
Any idea?
Edits:
I added a simple test example
Running the tests using NUnit agent I have the same behavior
Debugging it seems that the seeding is done once only
Using SQL profiler I can see the DB reset and seed done only once at the beginning
#Steve Fenton
Tests are failing because the database is empty so Testing to Read and Delete data doesn't work.
#Gert Arnold
No.
SOLUTION
I found the solution, that (after all) is pretty obvious.
Below you can see the final solution.
The key is the Database.SetInitializer that configure EF to initialize the database using the registered IDatabaseInitializers.
EF6 allow you to use Context.Database.Initialize(true); that forces the database to run all the initializers.
The boolean parameter set to True force to run the initializers even if those have been already run for the current context.
[SetUp]
public virtual void SetupInitialData()
{
var data = InitializeData();
Context = new FmsDbContext();
if (data != null)
{
Database.SetInitializer(new TestDataInitializer(data));
}
Context.Database.Initialize(true);
}
More info at: http://msdn.microsoft.com/en-us/library/system.data.entity.database.initialize%28v=vs.113%29.aspx
I found the solution, that (after all) is pretty obvious. Below you can see the final solution.
The key is the Database.SetInitializer that configure EF to initialize the database using the registered IDatabaseInitializers.
EF6 allow you to use Context.Database.Initialize(true); that forces the database to run all the initializers.
The boolean parameter set to True force to run the initializers even if those have been already run for the current context.
[SetUp]
public virtual void SetupInitialData()
{
var data = InitializeData();
Context = new FmsDbContext();
if (data != null)
{
Database.SetInitializer(new TestDataInitializer(data));
}
Context.Database.Initialize(true);
}
More info at: http://msdn.microsoft.com/en-us/library/system.data.entity.database.initialize%28v=vs.113%29.aspx

EntityFramework in test initialization error: CREATE DATABASE statement not allowed within multi-statement transaction

I'm trying to build a quick test that deletes and recreates a database every time it runs. I have the following:
[TestClass]
public class PocoTest
{
private TransactionScope _transactionScope;
private ProjectDataSource _dataSource;
private Repository _repository = new Repository();
private const string _cstring = "Data Source=.;Initial Catalog=test_db;Trusted_Connection=True";
[TestInitialize]
public virtual void TestInitialize()
{
_dataSource = new ProjectDataSource(_cstring);
_dataSource.Database.Delete();
_dataSource.Database.CreateIfNotExists();
_transactionScope = new TransactionScope();
}
[TestMethod]
public void TestBasicOperations()
{
var item = _repository.AddItem(new Item(){Details = "Test Item"});
// AddItem makes a call through the data context to add a set and then calls datacontext.SaveChanges()
}
[TestCleanup]
public void TestCleanup()
{
// rollback
if (_transactionScope != null)
{
_transactionScope.Dispose();
}
}
However when I run the test I get the following error:
Result Message: Test method
Project.Repository.UnitTests.PocoTest.TestBasicOperations threw
exception: System.Data.SqlClient.SqlException: CREATE DATABASE
statement not allowed within multi-statement transaction.
ProjectDataSource is here:
public class ProjectDataSource : DbContext, IProjectDataSource
{
public ProjectDataSource() : base("DefaultConnection")
{
}
public ProjectDataSource(string connectionString) : base(connectionString)
{
}
public DbSet<Set> Sets { get; set; }
}
Repository:
public class Repository : IRepository
{
private readonly ProjectDataSource _db = new ProjectDataSource();
public Item AddItem(Item item)
{
_db.Items.Add(item);
_db.SaveChanges();
return item;
}
}
Why is this happening?
Also - if it makes any difference - the error doesn't occur if I comment out the AddItem line in TestMethod.
You can also use db.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, sqlCommand);
See https://stackoverflow.com/a/24344654/375114 for details
For your information, this error occurs by design and it happens whenever non-transactionable commands are issued to Microsoft SQL Server within an active transaction.
The solution is, therefore, granting that Database.CreateIfNotExists() hits the database out of any transaction scope. Remember, SQL Profiler is your friend.
You can get a roughly updated list of commands that are not allowed to run whithin transactions.
Note: In case one wonders why am I providing a list based on a Sybase's product, bear in mind that Microsoft SQL Server shares most of its basic genetic with Sybase' engine. For further reading, refer to https://en.wikipedia.org/wiki/Microsoft_SQL_Server
In case anyone else runs into this issue:
In my Repository class, I have another definition of what's commonly labeled a "dbContext" - ProjectDataSource. This means that one context was created in my test class, while another was created in my Repository object. Sending the connectionstring to my repo class solved the problem:
In Repository:
public class Repository : IRepository
{
private readonly ProjectDataSource _db;
public Repository(string connectionString)
{
_db = new ProjectDataSource(connectionString);
}
public Repository()
{
_db = new ProjectDataSource();
}
From my test:
private TransactionScope _transactionScope;
private Repository _repository;
private ProjectDataSource _dataSource;
private const string _connectionString = "Data Source=.;Initial Catalog=test_db;Trusted_Connection=True";
[TestInitialize]
public virtual void TestInitialize()
{
_repository = new Repository(_connectionString);
_dataSource = new ProjectDataSource(_connectionString);
_dataSource.Database.Delete();
_dataSource.Database.CreateIfNotExists();
_transactionScope = new TransactionScope();
}
You can not use implicit commits around certain SQL commands.
Creating and Deleting databases is an example
SQL server will do an AUTOCommit
See the remarks section in the MS SQL help.
http://msdn.microsoft.com/en-us/library/ms176061.aspx
and something on Auto Commit for more info...
http://msdn.microsoft.com/en-us/library/ms187878%28v=sql.105%29
Try this code
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Suppress))
{
var sqlCommand = String.Format("Create DATABASE [{0}]", "TempBackupDB");
_context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, sqlCommand);
ts.Complete();
}
You need to run Update-Database command on package manager console.

Unit Testing without Database: Linq to SQL

I have a repository implemented using LINQ to SQL. I need to do Unit Testing though I don't have a database. How can I write the UT for FreezeAllAccountsForUser method? Can you please show an example using manually mocking?
Note: There is inheritance mapping used in domain objects
Note: Unit Testing is to be done using Visual Studio Team Test
Comment from #StuperUser. Unit testing involves completely isolating code from the other objects it interacts with. This means that if the code fails, you can be sure that the failure is to do with the code under test. To do this you have to fake these objects.
CODE
public void FreezeAllAccountsForUser(int userId)
{
List<DTOLayer.BankAccountDTOForStatus> bankAccountDTOList = new List<DTOLayer.BankAccountDTOForStatus>();
IEnumerable<DBML_Project.BankAccount> accounts = AccountRepository.GetAllAccountsForUser(userId);
foreach (DBML_Project.BankAccount acc in accounts)
{
string typeResult = Convert.ToString(acc.GetType());
string baseValue = Convert.ToString(typeof(DBML_Project.BankAccount));
if (String.Equals(typeResult, baseValue))
{
throw new Exception("Not correct derived type");
}
acc.Freeze();
DTOLayer.BankAccountDTOForStatus presentAccount = new DTOLayer.BankAccountDTOForStatus();
presentAccount.BankAccountID = acc.BankAccountID;
presentAccount.Status = acc.Status;
bankAccountDTOList.Add(presentAccount);
}
IEnumerable<System.Xml.Linq.XElement> el = bankAccountDTOList.Select(x =>
new System.Xml.Linq.XElement("BankAccountDTOForStatus",
new System.Xml.Linq.XElement("BankAccountID", x.BankAccountID),
new System.Xml.Linq.XElement("Status", x.Status)
));
System.Xml.Linq.XElement root = new System.Xml.Linq.XElement("root", el);
//AccountRepository.UpdateBankAccountUsingParseXML_SP(root);
AccountRepository.Update();
}
Repository Layer
namespace RepositoryLayer
{
public interface ILijosBankRepository
{
System.Data.Linq.DataContext Context { get; set; }
List<DBML_Project.BankAccount> GetAllAccountsForUser(int userID);
void Update();
}
public class LijosSimpleBankRepository : ILijosBankRepository
{
public System.Data.Linq.DataContext Context
{
get;
set;
}
public List<DBML_Project.BankAccount> GetAllAccountsForUser(int userID)
{
IQueryable<DBML_Project.BankAccount> queryResultEntities = Context.GetTable<DBML_Project.BankAccount>().Where(p => p.AccountOwnerID == userID);
return queryResultEntities.ToList();
}
public virtual void Update()
{
//Context.SubmitChanges();
}
}
}
Domain Classes
namespace DBML_Project
{
public partial class BankAccount
{
//Define the domain behaviors
public virtual void Freeze()
{
//Do nothing
}
}
public class FixedBankAccount : BankAccount
{
public override void Freeze()
{
this.Status = "FrozenFA";
}
}
public class SavingsBankAccount : BankAccount
{
public override void Freeze()
{
this.Status = "FrozenSB";
}
}
}
Auto generated Class by LINQ to SQL
[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.BankAccount")]
[InheritanceMapping(Code = "Fixed", Type = typeof(FixedBankAccount), IsDefault = true)]
[InheritanceMapping(Code = "Savings", Type = typeof(SavingsBankAccount))]
public partial class BankAccount : INotifyPropertyChanging, INotifyPropertyChanged
Simply, you can't. The sole purpose of the repository implementation is talking to the database. So the database technology does matter and you should perform integration tests.
Unit testing this code is impossible because LINQ to Objects is a superset of LINQ to SQL. You might have a green unit test and still get the runtime exception when using real db because you used a feature of LINQ in your repository that cannot be translated into SQL.
The Repository responsibility is to persist domain objects and fetch them on request. i.e. it's job is to take an object and deserialize/serialize it to from some form of durable storage.
So tests for the repository have to test against the real storage in this case a DB. i.e. these are integration tests - tests that your class integrates with the external DB.
Once you have this nailed, the rest of the client/app doesn't have to work against the real DB. They can mock the repository and have fast unit tests. You can assume that GetAccount works since the integration tests pass.
More details:
By passing in the Repository object as a ctor or method arg, you open the doors for passing in a fake or a mock. Thus now the service tests can run without a real repository >> there is no DB-access >> fast tests.
public void FreezeAllAccountsForUser(int userId, ILijosBankRepository accountRepository)
{
// your code as before
}
test ()
{ var mockRepository = new Mock<ILijosBankRepository>();
var service = // create object containing FreezeAllAccounts...
service.FreezeAllAccounts(SOME_USER_ID, mockRepository);
mock.Verify(r => r.GetAllAccountsForUser(SOME_USER_ID);
mock.Verify(r => r.Update());
}
You can by using the IDbSet interface in your datacontext and extracting an interface for your datacontext class. Programming towards interfaces is the key to creating unit testable code.
The reason that you would want to create unit tests for these linq queries is to have a unit test for the logical query. Integration tests are subject to all kinds of false negatives. The db not being in the right state, other queries running at the same time, other integration tests, etc. It is very hard to isolate a db well enough for a reliable integration test. That is why integration tests are so often ignored. If i have to pick one, i want the unit test...

EF 4.1 Code First doesn't initialize DB (DropCreateDatabaseAlways) when using Moq

I'm using Entity Frameworc 4.1 Code First and Moq. And I want to test database initializer. Also I have the abstract BaseUnitOfWork class which inherited from DbContext (so, for testing it should be mocked).
public abstract class BaseUnitOfWork : DbContext, IUnitOfWork
{
...
public IDbSet<User> Users
{
get
{
return Set<User>();
}
}
...
}
User is simple POCO with three properties: Id, Login, Password.
And here is the code of the DbInitializer:
public class BaseDbInitializer : DropCreateDatabaseAlways<BaseUnitOfWork>
{
protected override void Seed(BaseUnitOfWork context)
{
base.Seed(context);
context.Set<User>().Add(new User { Login = "admin", Password = "1" });
context.SaveChanges();
}
}
I'm trying to test this initializer with the next test (NUnit is used):
[TestFixture]
public class BaseDbInitializerTests
{
private BaseUnitOfWork _baseUnitOfWork;
[TestFixtureSetUp]
public void Init()
{
Database.SetInitializer(new BaseDbInitializer());
_baseUnitOfWork = new Mock<BaseUnitOfWork>(Consts.ConnectionStringName).Object;
_baseUnitOfWork.Database.Initialize(true);
}
[TestFixtureTearDown]
public void CleanUp()
{
_baseUnitOfWork.Dispose();
Database.Delete(Consts.ConnectionStringName);
}
[Test]
public void ShouldInitializeBaseDb()
{
var repository = new Mock<BaseRepository<User>>(_baseUnitOfWork).Object;
var firstUserInDb = repository.FindBy(x => x.Login == "admin" && x.Password == "1").SingleOrDefault();
Assert.That(firstUserInDb, Is.Not.Null);
Assert.That(firstUserInDb.Login, Is.EqualTo("admin"));
Assert.That(firstUserInDb.Password, Is.EqualTo("1"));
}
}
Unfortunately it seems like Seed method of the BaseDbInitializer class doesn't execute. DB is recreating, but there is no any records, and I tried to debug this test and Seed method was executed during debug session.
The strategy DropCreateDatabaseAlways<BaseUnitOfWork> is looking for an exact type match of BaseUnitOfWork, not a derived type, and not Mock<BaseUnitOfWork>. If you need it, you'll have to implement a copy of the strategy for the mocked type.
What is the point of mocking context and in the same time expecting database to exists? The point of mocking is removing dependency on the database (but it will not always work as expected).
So either use mock (unit test with all its problems) or database with real context and integration test.

Writing a testable "import data from database" class

I am tasked with pulling all the rows from a 3rd party vendor's SQLite data table, creating business objects from those records, and sending the new business objects off to another class.
Pseudo-code:
var databasePath = "%user profile%\application data\some3rdPartyVendor\vendor.sqlite"
var connection = OpenSqliteConnection(databasePath);
var allGizmoRecords = connection.Query(...);
var businessObjects = TransformIntoBizObjs(allGizmoRecords);
someOtherClass.HandleNewBizObjs(businessObjects);
I've got all that working.
My question is: How can I write this class so it's unit testable?
Should I:
use the repository pattern to mock out the data access
actually provide a dummy SQLite database in the unit test
Or any better ideas? I'm using C#, but this question seems rather language-agnostic.
You could inject a test-only Sqlite database quite easily, refactoring the code to look like below. But how are you asserting the results? The business objects are passed to someOtherClass. If you inject an ISomeOtherClass, that class's actions need to be visible too. It seems like a bit of pain.
public class KillerApp
{
private String databasePath;
private ISomeOtherClass someOtherClass;
public KillerApp(String databasePath, ISomeOtherClass someOtherClass)
{
this.databasePath = databasePath;
this.someOtherClass = someOtherClass;
}
public void DoThatThing()
{
var connection = OpenSqliteConnection(databasePath);
var allGizmoRecords = connection.Query(...);
var businessObjects = TransformIntoBizObjs(allGizmoRecords);
someOtherClass.HandleNewBizObjs(businessObjects);
}
}
[TestClass]
public class When_Doing_That_Thing
{
private const String DatabasePath = /* test path */;
private ISomeOtherClass someOtherClass = new SomeOtherClass();
private KillerApp app;
[TestInitialize]
public void TestInitialize()
{
app = new KillerApp(DatabasePath, someOtherClass);
}
[TestMethod]
public void Should_convert_all_gizmo_records_to_busn_objects()
{
app.DoThatThing();
Assert.AreEqual(someOtherClass.Results, /* however you're confirming */);
}
}
Using an IRepository would remove some of the code from this class, allowing you to mock the IRepository implementation, or fake one just for test.
public class KillerApp
{
private IRepository<BusinessObject> repository;
private ISomeOtherClass someOtherClass;
public KillerApp(IRepository<BusinessObject> repository, ISomeOtherClass someOtherClass)
{
this.repository = repository;
this.someOtherClass = someOtherClass;
}
public void DoThatThing()
{
BusinessObject[] entities = repository.FindAll();
someOtherClass.HandleNewBizObjs(entities);
}
}
[TestClass]
public class When_Doing_That_Thing
{
private const String DatabasePath = /* test path */;
private IRepository<BusinessObject> repository;
private ISomeOtherClass someOtherClass = new SomeOtherClass();
private KillerApp app;
[TestInitialize]
public void TestInitialize()
{
repository = new BusinessObjectRepository(DatabasePath);
app = new KillerApp(repository, someOtherClass);
}
[TestMethod]
public void Should_convert_all_gizmo_records_to_busn_objects()
{
app.DoThatThing();
Assert.AreEqual(someOtherClass.Results, /* however you're confirming */);
}
}
But this still feels quite cumbersome. There are two reasons, 1) the Repository pattern has been getting some bad press lately from Ayende, who knows a thing or two about Repository. And 2) what are you doing writing your own data access!? Use NHibernate and ActiveRecord!
[ActiveRecord] /* You define your database schema on the object using attributes */
public BusinessObject
{
[PrimaryKey]
public Int32 Id { get; set; }
[Property]
public String Data { get; set; }
/* more properties */
}
public class KillerApp
{
private ISomeOtherClass someOtherClass;
public KillerApp(ISomeOtherClass someOtherClass)
{
this.someOtherClass = someOtherClass;
}
public void DoThatThing()
{
BusinessObject[] entities = BusinessObject.FindAll() /* built-in ActiveRecord call! */
someOtherClass.HandleNewBizObjs(entities);
}
}
[TestClass]
public class When_Doing_That_Thing : ActiveRecordTest /* setup active record for testing */
{
private ISomeOtherClass someOtherClass = new SomeOtherClass();
private KillerApp app;
[TestInitialize]
public void TestInitialize()
{
app = new KillerApp(someOtherClass);
}
[TestMethod]
public void Should_convert_all_gizmo_records_to_busn_objects()
{
app.DoThatThing();
Assert.AreEqual(someOtherClass.Results, /* however you're confirming */);
}
}
The result is a much smaller class and a business object and data-layer that you can change more easily. And you don't even have to mock the database calls, you can configure and initialize ActiveRecord to use a test database (in-memory, even).
Well, the only thing that would really need to be tested here is TransformIntoBizObjs, I would think, since the connection code should have been written/tested elsewhere. Simply passing things that might show up to Transform and seeing if the right thing pops out would be what you need to do.
Remember to test all usecases of Transform, even potentially weird items that probably shouldn't end up in the function call, but might. Never know what people have been shoving in their databases.
Inversion of Control (IoC) and Dependency Injection (DI) will go a long way towards making your code more testable. There are a lot of frameworks out there that can assist you with this, but for your purposes you don't necessarily need to go to all that effort.
Start with extracting an interface that might look something like this:
Interface ISqlLiteConnection
{
public IList<GizmoRecord> Query(...);
}
Once you've done that, you should refactor the OpenSqlLiteConnection() method to return an instance of ISqlLiteConnection, rather than the concrete implementation. To test, just create a class that implements your interface, which mocks up the actual DB queries and connections with determinate results.
Databases are complicates, you need to test your query code and you need to test it against a real sqlite instance - otherwise you can't be sure you didn't hit some rare sqlite quirk or bug.
And since the only way to test your query is to run it on a real sqlite file, and it's really easy to include such a file with your test there's no point to adding another layer just to make it "more" testable or to have "pure" unit tests.
Just make sure to add all the strange edge cases you can think of to your sample file.

Categories