Reputation: 86957
what's the best practice for creating test persistence layers when doing an ASP.NET site (eg. ASP.NET MVC site)?
Many examples I've seen use Moq (or another mocking framework) in the unit test project, but I want to, like .. moq out my persistence layer so that my website shows data and stuff, but it's not coming from a database. I want to do that last. All the mocking stuff I've seen only exists in unit tests.
What practices do people do when they want to (stub?) fake out a persistence layer for quick and fast development? I use Dependency Injection to handle it and have some hard coded results for my persistence layer (which is really manual and boring).
What are other people doing? Examples and links would be awesome :)
Just a little update: so far I'm getting a fair bit of mileage out of having a fake repository and a SQL repository - where each class implements an interface. Then, using DI (I'm using StructureMap), I can switch between my fake repository or the SQL repository. So far, it's working well :)
(also scary to think that I asked this question nearly 11 months ago, from when I'm editing this, right now!)
Upvotes: 17
Views: 1535
Reputation: 435
I've gone the route of creating tables and data during a setup method in a unit test class, running tests, then doing clean up during the teardown. Yes, this method works, but if you really end up using your unit tests for debugging purposes, invariably you will run the setup, debug something then stop in the middle without doing the teardown. It's very brittle and you will probably end up (in the long run) with bad data in your test database and/or unusable unit tests. I personally think its best to mock the database layer using a mocking framework. I do understand that sometimes it's best to do logic in the database. For these cases you can use a tool like DBFit to write tests for your database layer.
Upvotes: 0
Reputation: 86957
I know this question is a bit old, but I've finally come up with an answer :)
Firstly, use RavenDb (Embedded). It's part of the RavenDb Document Database. Its a fully in memory database and works perfectly with unit tests :) I've done it with MSTest, NUnit and xUnit.
Secondly, you can use NHibernate with SqlLite if you don't want to use RavenDb. Ayende has a post about using this.
Upvotes: 0
Reputation: 35679
Assuming you're using the Repository pattern from Rob Conery's MVC Store Front:
http://blog.wekeroad.com/mvc-storefront/mvc-storefront-part-1/
I followed Rob Conery's tutorial but ran into the same want as you. Best thing to do is move the Mock Repositories you've created into a seperate project called Mocks then you can swap them out pretty easily with the real ones when you instantiate your service. If your feeling adventurous you could create a factory that takes a value from the config file to instantiate either a mock or a real repository,
e.g.
public static ICatalogRepository GetCatalogRepository(bool useMock)
{
if(useMock)
return new FakeCatalogRepository();
else
return new SqlCatalogRepository();
}
or use a dependency injection framework :)
container.Resolve<ICatalogRepository>();
Good luck!
EDIT: In response to your comments, sounds like you want to use a list and LINQ to emulate a db's operations e.g. GetProducts, StoreProduct. I've done this before. Here's an example:
public class Product
{
public int Identity { get; set; }
public string Name { get; set; }
public string Description { get; set; }
//etc
}
public class FakeCatalogRepository()
{
private List<Product> _fakes;
public FakeCatalogCatalogRepository()
{
_fakes = new List<Product>();
//Set up some initial fake data
for(int i=0; i < 5; i++)
{
Product p = new Product
{
Identity = i,
Name = "product"+i,
Description = "description of product"+i
};
_fakes.Add(p);
}
}
public void StoreProduct(Product p)
{
//Emulate insert/update functionality
_fakes.Add(p);
}
public Product GetProductByIdentity(int id)
{
//emulate "SELECT * FROM products WHERE id = 1234
var aProduct = (from p in _fakes.AsQueryable()
where p.Identity = id
select p).SingleOrDefault();
return aProduct;
}
}
Does that make a bit more sense?
Upvotes: 3
Reputation: 2433
I am using a complete in memory database with SQLite and ActiveRecord. Basically we delete and re-create the database before every integration test is being run, so that the data is always in a known state. The contents of the database are inserted through code. So an example would be like this:
ActiveRecord.Initalize(lots of parameters)
ActiveRecord.DropSchema();
ActiveRecord.CreateSchema();
and then we just add lots of customers or whatever, DDD style:
customerRepository.Save(customer);
Another way to solve this could be using NDbUnit to maintain the state of the database.
Upvotes: 0
Reputation: 3711
Although I'm not using Asp.Net or the MVC framework I do have the need to test services without hitting the database. Your question triggered the writing up of a short (ok, maybe not so short) summary of how I do it. Not claiming it's the best or anything, but it works for us. We access data through a repository and when required we plug in an in-memory repository as explained in the post.
Upvotes: 0
Reputation: 186
Boring or not, I think you're on the right track. I assume you're creating a fakeRepository that is a concrete implementation of your IRepository which in turn is injected into your service layer. This is nice because at some point in the future when you're happy with the shape of your entities and the behavior of your services, controllers, and views, you can then test drive your real Repositories that will use the database to persist those entities. Of course the nature of those tests will be integration tests, but just as important if not more so.
One thing that may be less boring for you when the time comes to create your real repositories is if you use nHibernate for your persistence you will be able let nhibernate generate your database after you create the nhibernate maps for your entities, assuming you don't have to use a legacy schema.
For instance, I have the following method that is called by my SetUpFixture to generate my db schema:
public class SchemaBuilder
{
public static void ExportSchema()
{
Configuration configuration = new Configuration();
configuration.Configure();
new SchemaExport(configuration).Create(true, true);
}
}
and my SetUpFixture is as follows:
[SetUpFixture]
public class SetUpFixture
{
[SetUp]
public void SetUp()
{
SchemaBuilder.ExportSchema();
DataLoader.LoadData();
}
}
where DataLoader is responsible for creating all of my seed data and test data using the real respoitory.
This probably doesn't answer your questions but I hope it serves to reassure you in your approach.
Greg
Upvotes: 0