I'm using NHibernate and the Repository pattern on a fairly large project and am trying to establish my service layer unit testing strategy and am having some problems getting in into my head. It's possible that I'm approaching the unit testing incorrectly, and it's also possible that I'm approaching the Repository pattern incorrectly, but I'm not sure which.
A simplified subset of my scenario looks like this:
public class UserRepository : RepositoryBase, IRepository
{
public UserRepository() {}
public UserRepository( ISession sessionParam ) {
session = sessionParam; // member of repository base
}
public string GetUsernameFromEmail( string emailAddress ) {
return session.QueryOver<Members>().List().Where( u => u.EmailAddress.ToLowerInvariant() == emailAdrress.ToLowerInvariant() ).FirstOrDefault().Username;
}
}
My unit testing concept would be that I would fake NHibernate's ISession and pass in one that returned a list of users that would fit the scenario I'm trying to test (for instance, email address is case-insensitive) (I also can't get this to work with FakeItEasy, but that's for another question, should I proceed down this path). Keeping in mind that we should not fake objects that we don't own, I can see the logic of not wanting to fake the ISession, and I've been reading a lot about how one shouldn't test the repository - that that's too far down for unit tests.
But even in this very basic case there's logic in the repository that I would like to unit test. Other repository methods will have potentially even more logic (data validation and the like, for instance). I know I can use SqlLite or something similar to build relatively fast integration tests for the reporitory, but it still seems to me that this logic should be unit tested.
Relying on the repository there is a (WCF) service tier that's being consumed by an Asp.Net MVC4 site.
In the best of all worlds I would build my unit tests in the WCF tier and fake away the IRepository for testing, but I don't see how I can move this logic to the service tier without getting all of the users from the repository and returning them to the service tier, which seems ridiculous.
So my question is: what piece of the overall architecture here do I have fundamentally wrong in my head?
EDIT
In response to #Wiktor-zychla's answer, here's my logic regarding why I wanted to fake ISession. In thinking about this specific test, I want to have my repository use an implementation of ISession which always returns a single user with a mixed-case email address and a specfic username, pass in an all lower-case email address, and have the return value be the username I instructed my fake to use. That way I am testing my logic against a know value - whether or not that's how NHibernate will operate in the real world isn't my concern here - testing the logic in the repository method is. And again, I know this is a trivial and naive example that could be solved in many other ways - it's just standing in for more complicated functionality that I want to be able to test later.
I don't think you should try to fake the ISession. This doesn't make much sense - the NHibernate repository is a concrete implementation of an abstract concept and what you want to test is that whether or not this concrete implementation is ok rather than abstract it even further and test what? A different, fake linq implementation and then pretend that NH follows it?
Your unit tests should involve a real database then, probably set up before the test starts so that you inject a temp ISession to the repository but still the ISession points to a real database.
On the other hand, it is perfectly valid to have yet another implementation of the repository to be injected in your service layer when you test the service which uses the repository.
Related
Sorry if I am asking very basic question,
I have set of web services (developed using .Net WebApi). These services are either business layer or data access layer APIs. These APIs are either dependent on other services or database itself.
I want to write unit test cases for it. I have following questions
As business layer APIs has dependency on data access service or some other service. If I write unit test just to invoke business API then it would invoke data access API. Is this the correct way to write unit test case? or should I inject all dependency object with unit test? I think earlier one would be integration test not unit test.
Should I write unit tests for Data access layer at all? I checked this link (Writing tests for data access code: Unit tests are waste) and it says DAL does not require unit tests. Should I still write tests for data access layer. I think it would be integration test not unit tests?
Question 1:
I would say if you want to do TDD, then it's not the "correct" way, because as you said, you would be performing integration tests. Then again, maybe you don't want to do TDD and integration tests are good enough for you, but to answer the question: this wouldn't be the proper way to **unit-**test your code.
Question 2
I would say it depends what you have in your data access layer. For instance, if you implement repositories, you will probably want to write a few tests.
Save method
You want to make sure that given an entity that you have retrieved from your repository, editing some properties of this entity and persisting the changes will actually save the modifications and not create a new entity. Now: you might think this is an integration test, but it really depends on how well designed your code is. For instance, your repository could be just an extra layer of logic on top of a low-level ORM. In that case, when testing the save method, what you will do is that you will assert that the right methods are called with the right parameters on the ORM service injected in your repository.
Errors and exceptions
While accessing data, it is possible to have problems such as connection to the database being broken, or that the format of the data is not as expected, or deserialization problems. If you want to provide some good error handling and perhaps create custom exceptions and add more information to them depending on the context, then you definitely want to write tests to make sure the corrext information is propagated
on the other hand
If your DAL is just a few classes that wrap a non-mockable ORM, and you don't have any logic in there, then perhaps you don't need tests, but it seems that this doesn't happen too often, you will pretty much always have a bit of logic that can go wrong and that you want to test.
I am working with TDD and all is going well. When I get to my actual Repository though I don't know how to test this.
Consider the code below - this is what I know I want to write but how do I tackle this in a test first way without doing integration testing.
public class UserDb : IUserDb
{
public void Add(User user)
{
using (var context = new EfContext())
{
context.Users.Add(user);
context.SaveChanges();
}
}
}
The link below by forsvarir is what I want to put as an answer. How I can do that?
http://romiller.com/2012/02/14/testing-with-a-fake-dbcontext/
The usual answer to these kinds of questions is:
Isolate the hard to test dependencies (the EF context)
Provide a fake implementation in your tests to verify the correct behaviour of the SUT
This all makes sense when you have interesting logic to test in your system under test. For your specific case, the repository looks like a very thin abstraction between your clean domain and EF-aware logic. Good, keep 'em that way. This also means that it's not really doing much work. I suggest that you don't bother writing isolated unit tests (wrapping EF DbContext seems like extra work that might not pull its weight).
Note that I'm not saying you shouldn't test this code: I often tend to test these thin repositories using a real database, i.e. through integrated tests. For all the code that uses these repositories however, I'd stick to isolated unit testing by providing fake repositories to the system under test. That way I have coverage on my repository code and test that EF is actually talking to my database in the correct way and all other tests that indirectly use these repositories are nice, isolated and lightning-fast.
What are you hoping to achieve by testing the 3rd party tool? You could mock out the context var fakeContext = A.Fake<IDbContext>(); and then assert that an attempt was made to write to the database. A.CallTo(() => fakeContext.SaveChanges()).MustHaveHappened();
The above example uses FakeItEasy mocking library.
I have the following method wherein the business layer is interacting with the data access layer and returning the collection object. I'm new to unit testing, but need to add automated unit tests to the solution. I read multiple articles and theory related to unit testing, but I'm confused with how to proceed. It would be really helpful If somebody can guide me with approach,
[DataObjectMethod(DataObjectMethodType.Select, true)]
public static WorkQueueBE GetItemByDetailsID(int detailsID)
{ return WorkQueueDB.GetItemByDetailsID(detailsID); }
This method gives call to GetItemsByDetailsID method in db layer, which in turn calls a stored procedure, gets the data from database, fills the collection and returns an object.
I'm gonna summarize the comments a bit as well as add some new thoughts. You write
This method gives call to GetItemsByDetailsID method in db layer,
which in turn calls a stored procedure, gets the data from database,
fills the collection and returns an object.
A comment to this is -> A unit test should only test an isolated part of your logic, that will say a single method. Not the entire flow, that's an integration test.
From what I see in your code snippet you use concrete classes. If you really want to make your application easy to test you need to use interfaces and abstract classes that can be instantiated to concrete classes as well as easily mocked and stubbed. An natural way on how to learn how to implement interfaces, abstract classes and concrete classes is to do Test Driven Development. Start with a small project and learn from there :)
If I would want to unit test your method that you've provided I would separate your logic from the data-access layer. This I would do by making the data-access layer classes implement interfaces of what they should do. This way I can mock the data-access layer and just return a specific snippet of data, just the part I need to create my unit tests for the business-layer method. After all, in this case I want to test the business-layer-method's logic, not the data-access-layer-method's.
It is quite tough to start doing unit-testing-friendly code but when you start getting a grip of you are gonna love it :)
This was a lot of theory and no concrete example because I think you need to start with a small project of your own and do it the TDD way, by doing this you will understand how everything works concerning unit testing.
Some links to get you started
https://msdn.microsoft.com/en-us/library/aa730844(v=vs.80).aspx
https://msdn.microsoft.com/en-us/library/ff847525(v=vs.100).aspx
http://www.codeproject.com/Articles/321154/Test-Driven-Development-TDD-in-Csharp
Also Pluralsight has some courses on this. Hope this helps!
I want to mock the below line of code(by MOQ in C#,MVC) :-
CustomerDto target = CustomerService.GetAllCustomer().FirstOrDefault(n => n.CustomerID == customer.CustomerID);
Where CustomerService.GetAllCustomer() function is the dependency in the controller method.
Where it is using FirstOrDefault() function.And in unit testing i have no clue how to mock it.
Can any one suggest me way for it ?
Mock(stub) your dependency only. In this case it is CustomerService, which should be some interface or abstract class implementation.
Make your GetAllCustomer method return some fake customers.
FirstOrDefault is a .NET Framework method which should not be tested (it is already tested by the framework developers)
IMO, you need to start decoupling your code by moving towards a more layered approach. I am not quite sure what you need to achieve by mocking the FirstOrDefault method. I suggest having three layers and their tests as below -
Data access - uses EF and its DB context and implements a data access interface. You should unit test this without mocking EF's db context. Tests for this layer would be "state" dependent. By that I mean, your tests will work with real data and database for the CRUD operations. You just need to make sure you do not persist the changes to the db after the test run. One can use Spring.Net's testing library to achieve this or simply run your tests under a transaction scope and roll back the transaction after every test run (in the clean up).
Business logic - contains the business logic and works with the data access interface. Use any DI framework like spring.net or ms unity to inject the data access layer. You should unit test this by trying to avoid actual database calls. This is where something like a NMock, Rhinomock or MOQ comes into picture. Set up boundary and exception conditions using mocks and make sure your business logic addresses all the concerns.
MVC Controller - Will delegate the calls to business logic layer and most probably handle stuff like notifications etc needed on the UI. It should be a judgement call if the controller really needs to be unit tested. It could be an overkill more than often. I would rather suggest considering automated UI test cases using something like selenium or Microsoft's coded UI tests.
I've got NHibernate-based (constructor ISessionFactory injection) generic repository implementation which is stored inside DAL. It implements contract which is stored in `Domain Layer'.
Should I test real repository behavior using SQl CE or should I refactor my application to support agnostic-like (like in Tim Maccharty's book http://www.wrox.com/WileyCDA/WroxTitle/productCd-0470147563,descCd-authorInfo.html) Unit of Work and then give my fake implementation of IUnitOfWorkRepository?
Is it a valid approach to run tests on a local database exposing real repository implementation?
Thanks!
The issue is what your are testing and why. That will answer the question.
If:
I want to test a third party tool
That is, are you testing if NHibernate is working (not a kind of test
I do). Then do whatever it requires, so refactoring not required. Loose yourself.
I want to test how my code interacts with a thrid party tool
Then you are talking about what I like to call a interaction test. Refactoring is required as your more interested in how your using NHiberate than if it works.
I want to test my code
The abstract NHibernate entirely. Do whatever is necessary ... wrapper? Your now back into unit testing.
I want to test my application from a user point of view
I think this is above the scope your talking. But you can use this scope talking about components. So ... hmmm ... worthwhile but not easy. Not a unit test, so you want to instantiate the component/app and run the whole thing as its 'user' does. I call these 'UATs' and usually implement as 'Coded UATs'.
A unit test is testing a unit in isolation. So, no, it's not even a unit test if you're going to the database.
Abstract away and test your repositories with mocked up interfaces.
I think to test the repositories you need to use the actual scenario. Otherwise you don't have any other place to test the database access. Mocking the repositories is not a good practice. Because you don't have any logic which is need to test in the repositories. I think you need to write integration tests which is calling actual repositories to have any benefit from it.