Questions about TDD
Environment
In my solution I have three projects, they are:
- Web (Asp.net MVC4)
- Model (Class library)
- Test (Test project)
In Model project have:
Couple
= Class
IRepository
= Interface-based repository
ICoupleRepository
= Interface Repository couple
Implementation
repository = CoupleRepository couple
In Test project have:
Fake/CoupleRepository
= Fake implementation of Repository couple (inside the folder Fake).
CoupleTest
couple class = Test
Behavior
By adding a couple under, need to modify some properties and also add a couple object also add other objects to the database.
I put this logic into the CoupleRepository
(not fake) repository in Add
method, I set these properties, add the object couple and two other objects.
public class CoupleRepository : ICoupleRepository
{
public void Add(Couple couple)
{
couple.Bride.Gender = Gender.Female;
couple.Groom.Gender = Gender.Male;
db.Couples.Add(couple);
db.Users.Add(new User{ CoupleID = couple.Bride.ID });
db.Users.Add(new User{ CoupleID = couple.Groom.ID });
db.SaveChanges();
}
}
Question
In my test class, CoupleTest
, need to test the addition of these users as well, and the modification of the properties.
Create a fake repository for my forehead it will not help me, really need to test code that is in default CoupleRepository.
What is the tip you give me?
Where Mocks and Stubs come in all this?
Where would this logic to save a couple?
I have to test repositories? Perhaps the ideal would be to test the controllers?
Many questions, I know =)
I'm new to TDD and do not know if I'm going in the right direction.
Test the default repository would not be ideal, since it accesses the database.
Main issue here is that you mix different layers. Repository is a intermediate level between Business Logic and storage. If your case, repository performs actions which are the part of Business logic. That's why you're forced to mimic that in your tests.
In general your entity should be fully constructed prior to saving. Repository should only save it (probably, invoking Validate method, if you need that).
This code:
couple.Bride.Gender = Gender.Female;
couple.Groom.Gender = Gender.Male;
should be moved to Couple business logic (constructor, for example).
From the more global point of view, with TDD you make mocks around the functionality you want to test. With your current approach you'll probably have something like IView -> Couple class -> IRepository
chain. That means that by mocking those interfaces, you intend to test Couple class (or business logic work in general).
To test the repository, you need a structure like Couple class -> CoupleRepository -> IDatabaseDriver
sequence. By mocking IDatabaseDriver
you'll be able to verify SqlCommands or Queries generated by real implementation of CoupleRepository.
In that case you'll write tests like (very simplistic sample):
var driver = new MockDatabaseDriver();
var repo = CoupleRepository(MockDatabaseDriver);
repo.Add(new Couple());
Assert.AreEquals("Insert into COUPLES values ('bride', groom')", driver.SqlQueryText);
Here MockDatabaseDriver doesn't execute queries, just indicates actions performed by repository.
精彩评论