I am also not an expert, and I only did TDD for a while, so take what I write in this incoherent answer, with a spoonful of salt :) I'm sure someone else can indicate if I have committed any really bad mistakes or pointed you in the wrong direction ...
I am not sure if your test is really Unit Test, because it performs several dependencies. Suppose you run this test and get an exception thrown from the method. Is this exception excluded from
- RepositoryHelper.GetTake2Repository ()) throwing? (Question of release)
- Call constructor ProjectCrewsByProjectSpec? (Addiction problem)
- rep.GetList (spec) throwing? kendo (is it kendo, right?) (addiction problem)
- ToDataSourceResult () throw? (Behavioral issue)
Unit testing is testing for complete isolation from their dependencies, so for now I would say that it is more like an integration test in which you don't care how the systems interact, you just want to make sure that for this projectID, seasonId and episodeId you return the expected results - in this case, the rep.GetList () method is really tested in combination with the ToDataSourceResult extension.
Now integration tests are very useful and 100% necessary as part of a test-based methodology, and if this is what you really want to do, then you are doing it right. (I put it and expect it to be back, did I get it back?)
But if you want Unit Test this code (in particular, if you want to use the Unit Test method of your GetProjectBySpec classes), you will need to do this as @jimmy_keen and reorganize it so that you can test the behavior of GetProjectBySpec. for example, here is a certain behavior that I just came up with, of course, yours may be different:
- If the input is bad, throw an ArgumentException
- Creates a new ProjectCrewsByProjectSpec
- Calls rep.GetList and passes the specification
- Returns a nonzero DataSourceResult
The first thing you need to do to verify that GetProjectBySpec does all the things in the list above is to reorganize it so that it does not create its own dependencies - instead, you give it the dependencies it needs Injection Dependency .
DI really works best when you inject the interface, so in any class that provides this method, your constructor for this class should take an instance, for example, IRepositoryHelper , and store it in a private readonly member, It should also take an instance of IProjectCrewsByProjectSpecFactory , which you would use to create your specification. Now, since you want to check what GetProjectBySpec really does with these dependencies, then you will use a mocking structure such as Moq , which I will not enter, except for the example below.
If none of these classes currently implements such an interface, just use Visual Studio to retrieve the interface definition for you based on the class definition. If they are third-party classes that you have no control over, this can be tricky.
But let me assume that you can define interfaces this way: (carry me on common bits, which I never 100%, I'm sure someone smarter than me can tell you where all the "T" should go ... ) The code below is not verified and not verified for typos!
public interface IRepositoryHelper<ProjectDGACrew> { IList<ProjectDGACrew> GetList(IProjectCrewsByProjectSpecFactory spec); } public interface IProjectCrewsByProjectSpecFactory { ProjectDGACrew Create(int projectId, int seasonId, int episodeId); }
Then your code will look something like this:
//somewhere in your class definition private readonly IRepositoryHelper<T> repo; private readonly IProjectCrewsByProjectSpecFactory pfactory; //constructor public MyClass(IRepositoryHelper<ProjectDGACrew> repo, IProjectCrewsByProjectSpecFactory pfactory) { this.repo = repo; this.pfactory=pfactory; } //method to be tested public DataSourceResult GetProjectBySpec(int projectId, int seasonId, int episodeId) { var spec = pfactory.Create(projectId, seasonId, episodeId); var personList = repo.GetList(spec).Select(p => new {//big query...}).ToDataSourceResult(); return personList; }
You now have 4 test methods for writing:
[TestMethod] [ExepctedException(typeof(ArgumentException)] public void SUT_WhenInputIsBad_ThrowsArgumentException() { var sut = new MyClass(null,null);
Hope that helps you ... and, of course, you can reorganize your test classes to avoid a lot of mocking tweaks and have it all in one place to minimize lines of code.