If you want to go the TDD way and you really want to ensure testability in your code, you have to get rid of your static
classes. Another point is that if you are going TDD you should start writing tests and let the design emerge, while here you already have a solid idea on how you want your design to be...
As you pointed out yourself, the DAL will be tested three times this way, but that is not the worst part. The worst part is that you cannot be able to test the ApiController or the BLL in isolation, which means that if something goes wrong in the test you won't have an idea of what class is failing and that defeats the purpose of unit testing: quickly pinpoint the reason of failure.
What I would do is something like this:
ICarDAL (interface) -> SelectCar, SelectCars, InsertCar, UpdateCar, DeleteCar
CarDAL will implement the above interface.
ICarBLL (interface) -> GetCar, GetCars, PostCar, PutCar, DeleteCar
Let's gloss over the fact that the BLL mirrors the Api methods. In my idea the BLL should provide logic independently from the using layers, so maybe methods like: GetCars, AddCar, EditCar, CreateCar... maybe just the names are different but even that is important: the moment this BLL gets used into a desktop application, for example, then PostCar and PutCar become meaningless.
CarBLL implements the above. Since CalBLL uses the DAL, its constructor will look something like this:
public CarBLL(ICarDAL dal)
{
this.dal = dal;
}
For the controller:
CarApiController -> GetCar, GetCars, PostCar, PutCar, DeleteCar
CarApiController will have a similar constructor:
public CarApiController(ICarBLL bll)
{
this.bll = bll;
}
The call stack remains the same but now your code is decoupled. Note that to use a parameterized constructor in the ApiController you need to register some sort of IoC container in your application. I have used Unity in the past with great satisfaction.
Now we can dance. Our tests will look something like this:
Controller tests:
public void test_that_this_works()
{
ICarBLL mock = new FakeCarBLL();
var controller = new CarApiController(mock);
Assert.That(controller.GetCars.Count(), Is.EqualTo(1));
}
With the above, you can just write a fake implementation of the BLL interface that always returns the same result and you can check that the operation in the controller are performing ok.
The BLL tests will look similar but you will use a fake implementaion of the DAL to simulate a set of results coming from the DB and maybe verify that the Save and Select methods are called the correct number of times (in that case I would suggest a mocking library, for example RhinoMocks)
Sorry for the very long answer but it is a very complex and extensive subject... good luck and happy coding! :)