views:

138

answers:

5

Example

I have a repository class (DAL):

public class MyRepository : IMyRepository
{
    public void Delete(int itemId)
    {
        // creates a concrete EF context class
        // deletes the object by calling context.DeleteObject()
    }

    // other methods
}

I also have a service class (BLL):

public class MyService
{
    private IMyRepository localRepository;

    public MyService(IMyRepository instance)
    {
        this.localRepository = instance;
    }

    public void Delete(int itemId)
    {
        instance.Delete(itemId);
    }

    // other methods
}

Creating a unit test for MyRepository would take much more time than implementing it, because I would have to mock Entity Framework context.

But creating a unit test for MyService seems nonsense, because it only calls into Repository. All I could check is to verify if it did actually call repository Delete method.

Question

How would you suggest to unit test these pair of Delete methods. Both? One? None? And what would you test?

+1  A: 

Yes, both.

IMyRepository mock = ...;
// create Delete(int) expectation

MyService service = new MyService(mock);
service.Delete(100);

// Verify expectations

Your Delete method right now might only call the Delete method on the repository, but that doesn't mean it always will. You want to have unit tests for this partly to verify it behaves correctly and partly as way of defining your specifications of how the repository is to work.

You also aught to have a test that verifies that the constructor will throw an exception if the repository is null. You might also have other validation to do here in this method such as non-negative ID's, or non-zero id. Maybe that doesn't happen here, make it part of the specifications by creating tests that verify the expected behaviors.

They seem trivial but I can all but guarantee it will change one day and your expectation and specifications may not be verified.

justin.m.chase
Well all you did in your example was a Service.Delete() test. You mocked my repository and tested Service that it actually calls into repository.
Robert Koritnik
What I meant with my previous comment is that you said "both" but only wrote code to test service layer. But yes, service is tested in your case.
Robert Koritnik
Sorry yes, I would then have another set of tests for testing the concrete repository, which may be more difficult since you're probably dependent upon 3rd party libraries and other layers. Those tests may end up being more like integration tests. So both, strive for total code coverage. But I don't think you can neglect this class since this is the abstraction you will be coding your app against.
justin.m.chase
A: 

Create the test for the Service. Currently all it does is to call into the Repository Delete method; however, you shouldn't care about that. What if later something happens and the functionality becomes much more complicated? Don't you want to have unit test code that will assure you that the functionality is still working as expected?

If you're exposing your Delete through your Service, you're expecting it to have an effect. Write a Unit Test to test that effect. Depending on your particular needs, I'd say you might not need to have a test on the Repository Delete, particularly if that functionality is getting exercised as part of your Service Delete functionality, but it really all depends on what level of coverage you're trying for.

McWafflestix
But if I unit test Service.Delete() method, all I can do is to verify that it calls Repository.Delete() method. I can't check any data, because data manipulation is done in repository.
Robert Koritnik
Is it sufficient to know that the Service.Delete() calls Repository.Delete()? Then you're fine with just Service.Delete(). Do you need to check data? Then you're going to need some level of mocking to check that data gets modified.
McWafflestix
+1  A: 

Yes, I would definitely write a unit test for the Service Layer. The reason for this is because, you're not just testing that your implementation works now, but you're also testing that it will continue to work in the future.

This is a vital concept to understand. If someone comes along later on and changes your ServiceLayer, and there's no unit test, how can you verify that the functionality continues to work?

I would also write tests for your DAL, but I would put those in a separate assembly called DataTests or something. The purpose here is to isolate your concerns across assemblies. Unit Tests shouldn't be concerned with your DAL, really.

Joseph
But if I unit test Service.Delete() method, all I can do is to verify that it calls Repository.Delete() method. I can't check any data, because data manipulation is done in repository. Other (future) complexities will not be included in the test.
Robert Koritnik
@Robert That's not entirely correct. You would need to create a mock IMyRepository object. Once you've done that, you can set up your mock so that when the service layer calls delete on it, you can verify that the delete is called on the mock correctly. Therefore, you're testing the Service.Delete functionality without testing the Repository.Delete as well.
Joseph
A: 

Also, if you had created this code with TDD, you would have had a test. It actually matters whether people can call Delete through your service, so you actually have to test it.

John Saunders
A: 

In my opinion you need to test both. Maybe you can do the creation EF context class in a seperate factory that can be tested more easy and mock the context class for the MyRepository tests. That will be more easy and using a factory for creating a context calls seems to be quiet useful for me.

crauscher
I would, but as I can google on the net, mocking Entity Framework context is a pain in the a...
Robert Koritnik