I am working through the book Professional ASP.NET MVC 2 and I am trying to get the unit testing in chapter 1 to work correctly; howver, I am getting some very strange errors.
T开发者_JS百科here are two projects in the solution: NerdDinner, and NerdDinner.Tests.
In the NerdDinner Project I have the following interface:
IDinnerRepository.cs
//...
namespace NerdDinner.Models
{
interface IDinnerRepository
{
//...
}
}
Also in the NerdDinner project, I have the following class:
//...
using NerdDinner.Models;
//...
namespace NerdDinner.Controllers
{
public class DinnersController : Controller
{
IDinnerRepository dinnerRepository;
// Default constructor
public DinnersController() : this(new DinnerRepository()){} // DinnerRepository is another concrete implementation of IDinnerRepository
//Test constructor
public DinnersController(IDinnerRepository repository) {
dinnerRepository = repository;
}
}
}
In the NerdDinner.Tests project, I have the following concrete implementation of IDinnerRepository:
//...
using NerdDinner.Models;
//...
namespace NerdDinner.Tests.Fakes
{
class FakeDinnerRepository : IDinnerRepository
{
//...
public FakeDinnerRepository(List<Dinner> dinners)
{
//...
}
//...
}
}
Now for the actual unit test (in NerdDinner.Tests)
using NerdDinner.Controllers;
//...
using NerdDinner.Models;
using NerdDinner.Tests.Fakes;
namespace NerdDinner.Tests
{
[TestClass]
public class DinnersControllerTest
{
List<Dinner> CreateTestDinners()
{
//...
}
DinnersController CreateDinnersController()
{
return new DinnersController(new FakeDinnerRepository(CreateTestDinners()));
}
}
}
And now for the actual problem: In the method CreateDinnersController in the class DinnerControllerClass, I am getting the following error:
DinnersController.DinnersController(NerdDinner.Models.IDinnerRepository repository) (+ 1 overload(s)) Error: The best overloaded method match for 'NerdDinner.Controllers.DinnersController.DinnersController(NerdDinner.Models.IDinnerRepository)' has some invalid arguments.
It gives me the option to create a constructor stub in DinnersController. It generates the following code:
private global::NerdDinner.Tests.Fakes.FakeDinnerRepository repository;
//...
public DinnersController(global::NerdDinner.Tests.Fakes.FakeDinnerRepository repository)
{
// TODO: Complete member initialization
this.repository = repository;
}
Even after generating that code, I still get the same error. But why should I even need that code anyway? As far as I can tell, I am doing everything correctly.
Can anybody help me figure out what is going on here?
Edit The generated code is giving the following error:
The type or namespace 'Tests' does not exist in the namespace 'NerdDinner' (are you missing any assembly reference?)
From what you've shown the IDinnerRepository
interface is not public meaning that it is not visible from your unit test. I would recommend you making it public as I suspect you have two different interfaces : one defined in the unit test and one in your project which conflict. Also I would recommend you to avoid relying on Visual Studio generate all the crap reflection code in order to test private and internal members.
The last error you're getting is due to there being no reference from the production code to the test code - but that's appropriate. You don't want that extra constructor.
Instead, you need to find out why the existing constructor taking an IDinnerRepository
isn't being used. Are you sure you only have one interface called IDinnerRepository
? If you go to the FakeDinnerRepository
source, go to the declaration, put the cursor in IDinnerRepository
and hit F12 (go to definition) does it go to the right place?
If you add a new member to IDinnerRepository
(just for the sake of testing: void Foo();
would be fine) does it cause both the production and fake implementation to fail to compile?
精彩评论