I'm quite new to TDD and I've been looking into mock frameworks. I understand the idea of mocking a database to give you data that you would receive from a database using either tables or a stored procedure for data that would already exist in a database.
However, how would you use this for creating records and inserting data? Surely you need to test that your create methods are tested and without a database how would you do this?
So I'm guessing that the interface IRepository will have a method in it called Save which will be implemented by the class ThingToTest. ThingToTest uses the object it is given to perform a kind of fictional save? SomeObject I'm guessing will just be a data
object (e.g it may be a Product class used to map to a Product table). Am I right so far?
So I'm guessing that the interface IRepository will have a method in it called Save which will be implemented by the class ThingToTest. ThingToTest uses the object it is given to perform a kind of fictional save? SomeObject I'm guessing will just be a data
object (e.g it may be a Product class used to map to a Product table). Am I right so far?
Almost... the ThingToTest uses the IRepository. The IRepository is an inteface to abstract the DB so that you can mock it when testing. I guess that was the piece I assumed you understood. For all the layers in your app you need to decouple them and interfaces
is the typical apporach. So the ThingToTest doesn't hit the DB directly, instead you have a repository object do that work and the coupling is via the interface. We use an interface because then in the test you can implement a fake (or use a mock).
So then to wire these all up, the ThingToTest doesn't create the concrete repository -- instead we pass it in as a ctor param (again so that in the tests the mock can be passed instead of a real DB/repository).
Ok I guess that makes more sense. So from your explanations and my understanding might an implementation of that looks like this:
Test:
[Test]
public void TestMock()
{
Mock<IRepository> mockRepository = new Mock<IRepository>();
var subject = new ThingToTest(mockRepository.Object);
var someObj = new SomeObject();
mockRepository.Verify(x => x.Save());
}
IRepository:
public interface IRepository
{
void Save();
}
Thing to Test:
public class ThingToTest
{
private IRepository _repository;
public ThingToTest(IRepository repository)
{
this._repository = repository;
}
public void SaveIt()
{
_repository.Save();
}
}
Some Object:
class SomeObject : IRepository
{
public SomeObject()
{
}
public void Save()
{
// Fake save
}
}
All was good up until the last class "ThingToSave". This is just an object that models the data to/from the database, so it'd be the paramater in and out of the repository. It doesn't implement any interfaces in this picture.
In addition to mocks, you can just write a fake repository that implements IRepository and store the data in a collection, like a List<T>. In this case you can add, remove and perform all the operations and they will be executed against an in-memory object
instead of a database. Now it's important to note that you are not testing database access calls so it's ok to use this fake, instead you are verifying that controller or service has correctly called methods in the IRepository.
Cerberus2589
Member
259 Points
144 Posts
Database Mocking
Mar 27, 2012 06:56 PM|LINK
I'm quite new to TDD and I've been looking into mock frameworks. I understand the idea of mocking a database to give you data that you would receive from a database using either tables or a stored procedure for data that would already exist in a database. However, how would you use this for creating records and inserting data? Surely you need to test that your create methods are tested and without a database how would you do this?
Thanks
BrockAllen
All-Star
28072 Points
4996 Posts
MVP
Re: Database Mocking
Mar 27, 2012 07:13 PM|LINK
The mocking frameowrks have APIs to validate if they were invokes. I use Moq, so the test would be something like:
void Test()
{
Mock<IRepository> mockRep = new Mock<IRepository>();
var subject = new ThingToTest(mockRep.Object);
var someObj = new SomeObject();
subject.SaveIt(someObj);
mockRep.Verify(x=>x.Save());
}
This is all pseudo-code :) but the point is that the last line is asking the mock to confirm that its Save was called. It fails the test if it wasn't.
Scroll down to "Verification" in the docs.
DevelopMentor | http://www.develop.com
thinktecture | http://www.thinktecture.com/
Cerberus2589
Member
259 Points
144 Posts
Re: Database Mocking
Mar 27, 2012 07:23 PM|LINK
Right but the Save method may actually have code to save data to the database. Surely this would actually try and run code to save to a real database?
BrockAllen
All-Star
28072 Points
4996 Posts
MVP
Re: Database Mocking
Mar 27, 2012 07:28 PM|LINK
No it wouldn't because the database part is mocked (that's the IRepository). See how I pass in the repository as the ctor parm to the ThingToTest?
Point is -- we're testing the "ThingToTest" class, not the DB and that's why we mock the DB layer (the repository).
DevelopMentor | http://www.develop.com
thinktecture | http://www.thinktecture.com/
Cerberus2589
Member
259 Points
144 Posts
Re: Database Mocking
Mar 27, 2012 07:44 PM|LINK
Thanks for your help, I think I'm getting there.
So I'm guessing that the interface IRepository will have a method in it called Save which will be implemented by the class ThingToTest. ThingToTest uses the object it is given to perform a kind of fictional save? SomeObject I'm guessing will just be a data object (e.g it may be a Product class used to map to a Product table). Am I right so far?
BrockAllen
All-Star
28072 Points
4996 Posts
MVP
Re: Database Mocking
Mar 27, 2012 07:51 PM|LINK
Almost... the ThingToTest uses the IRepository. The IRepository is an inteface to abstract the DB so that you can mock it when testing. I guess that was the piece I assumed you understood. For all the layers in your app you need to decouple them and interfaces is the typical apporach. So the ThingToTest doesn't hit the DB directly, instead you have a repository object do that work and the coupling is via the interface. We use an interface because then in the test you can implement a fake (or use a mock).
So then to wire these all up, the ThingToTest doesn't create the concrete repository -- instead we pass it in as a ctor param (again so that in the tests the mock can be passed instead of a real DB/repository).
DevelopMentor | http://www.develop.com
thinktecture | http://www.thinktecture.com/
Cerberus2589
Member
259 Points
144 Posts
Re: Database Mocking
Mar 27, 2012 08:36 PM|LINK
Ok I guess that makes more sense. So from your explanations and my understanding might an implementation of that looks like this:
Test:
[Test] public void TestMock() { Mock<IRepository> mockRepository = new Mock<IRepository>(); var subject = new ThingToTest(mockRepository.Object); var someObj = new SomeObject(); mockRepository.Verify(x => x.Save()); }IRepository:
public interface IRepository { void Save(); }Thing to Test:
public class ThingToTest { private IRepository _repository; public ThingToTest(IRepository repository) { this._repository = repository; } public void SaveIt() { _repository.Save(); } }Some Object:
class SomeObject : IRepository { public SomeObject() { } public void Save() { // Fake save } }BrockAllen
All-Star
28072 Points
4996 Posts
MVP
Re: Database Mocking
Mar 27, 2012 08:38 PM|LINK
All was good up until the last class "ThingToSave". This is just an object that models the data to/from the database, so it'd be the paramater in and out of the repository. It doesn't implement any interfaces in this picture.
DevelopMentor | http://www.develop.com
thinktecture | http://www.thinktecture.com/
Cerberus2589
Member
259 Points
144 Posts
Re: Database Mocking
Mar 27, 2012 08:45 PM|LINK
Did you mean the class SomeObject?
CodeHobo
All-Star
18669 Points
2648 Posts
Re: Database Mocking
Mar 27, 2012 08:51 PM|LINK
In addition to mocks, you can just write a fake repository that implements IRepository and store the data in a collection, like a List<T>. In this case you can add, remove and perform all the operations and they will be executed against an in-memory object instead of a database. Now it's important to note that you are not testing database access calls so it's ok to use this fake, instead you are verifying that controller or service has correctly called methods in the IRepository.
Blog | Twitter : @Hattan