say I have a function:
public List<Car> GetFourWheelDrives()
{
return dataContext.Cars.Where(c => c.IsFourWheelDrive == true).ToList();
}
Firstly it’s kind of obvious what I’m trying to do here. Any suggestions on how I’m doing this? Any improvements?
So now I want to unit test this. Well is it a unit test? A unit test isn’t suppose to touch the database right? So this is a functional test?
So say I write a test
[Test]
public void GetFourWheelDrives_NoParameters_ReturnAListOfOnlyCarsThatAreFourWheelDrives
{
Assert.Greater(dataContext.Cars.Where(c => c.IsFourWheelDrive == false).ToList().Count, 0);
var cars = GetFourWheelDrives();
Assert.Greater(cars.Count, 0);
Assert.AreEqual(cars.Count, cars.Where(c => c.IsFourWheelDrive == true).ToList().Count);
}
So first Assert I’m making sure cars that aren’t 4WD exist in the database otherwise it wouldn’t be a valid test.
Second Assert I’m making sure at least one was returned.
Third Assert I’m making sure that all the cars returned were in fact 4WD.
I know this isn’t a good test because I’m using the same logic in the test as the function I’m testing. However this is the only way I can currently think of to do this.
Can anybody tell me how to test this properly?
Thanks!
Well, according to one school of TDD, that’s exactly what you should do; write tests that incorporate the logic you’re developing, then refactor the logic out of the test and into a production class.
However, I would not call what you are doing a unit test, because unit tests by definition should not touch external resources like databases, file systems, and other “integration points”. Those are “integration tests”, and though they’re just as useful, you should always try to write the most side-effect-free tests you can that will prove the code works as designed.
Look at what you’re testing. Basically, you want to ensure that the function queries your Linq datasource for cars that are four-wheel drive, and not any other type. Assume, for just a minute, that Linq2SQL knows full well how to turn this Linq statement into a SQL query against your DB. You don’t need to test that; what you DO need to test is that the correct query is made from your code against the datasource.
To do this, you should implement a mock. A mock is a testing object that stands in for an external resource, and can be told to expect certain calls to its methods and behave in a certain way. Here, you should mock the datasource object. In order to be able to do this, the class containing GetFourWheelDrives() must be given this object from outside its scope; if it new()s one up, you’re “tightly coupled” to the Linq2SQL provider and cannot write a true unit test (you could still write it as an integration test if you can point Linq2SQL at a testing DB). Given that you can pass in the datasource used, you should give it a mock that expects to have its Cars property accessed, and returns an array of Cars objects as an IQueryable. You can define this array, meaning you have control over the data the query is executing against, and thus you can test that the query returned exactly the objects it should return.
Using Rhino.Mocks, your code might look like this:
This test effectively proves that given a set of cars of arbitrary size, your function will return only, and exactly, those cars that are 4WD, without needing a real DB to do so. This is what your unit tests should look like in cases where the class you’re testing has dependencies on external code.