1

First, I apologize for the open-ended nature of this question. However, I've been paralyzed by this for months, and in spite of consent searching, still cannot get past this.

I have been working on an MVC/EF app for a while. I'm trying to get an understanding on how to design and build a testable MVC3 application backed by Entity Framework (4.1). You can see a few questions I've asked on the subject here, here, and here.

I'm trying not to over complicate it, but I want it to be a sound, loosely coupled design that can grow. The way I understand it, the following are pretty much bare minimum required components:

MVC app
This is very thin. As little logic as possible goes here. My views have as little conditional logic as possible, my view models are never more than POCOs, and my controllers simply handle the mapping between the view models and domain models, and calling out to services.

Service layer + interfaces (separate assemblies)
This is where all of my business logic goes. The goal of this is to be able to slap any thin client (forms app, mobile app, web service) on top of this to expose the guts of my application. Interfaces for the service layer sits in another assembly.

Core utilities/cross-cutting + interfaces (separate assemblies)
This is stuff I build that is not specific to my application, but is not part of the framework or any third party plugin I'm using. Again, interfaces to these components sit in their own assembly.

Repository (EF context)
This is the interface between my domain models and my database. My service layer uses this to retrieve/modify my database via the domain models.

Domain models (EF POCOs)
The EF4 generated POCOs. Some of these may be extended for convenience to other nested properties or computed properties (such as Order.Total = Order.Details.Sum(d => d.Price))

IoC container
This is what is used for injecting my concrete/fake dependencies (services/utilities) into the MVC app & services. Constructor injection is used exclusively throughout.

Here is where I'm struggling:

1) When integration testing is appropriate vs. unit testing. For example, will some assemblies require a mix of both, or is integration testing mainly for the MVC app and unit testing for my services & utilities?

2) Do I bother writing tests against the repository/domain model code? Of course in the case of POCOs, this is not applicable. But what about when I extend my POCOs w/ computed properties?

3) The proper pattern to use for repositories. I know this is very subjective, as every time I see this discussed, it seems everyone has a different approach. Therefore it makes it hard to figure out which way to go. For example, do I roll my own repositories, or just use EF (DbContext) directly?

4) When I write tests for my services, do I mock my repositories, or do I use SQL Lite to build a mock database and test against that? (See debates here and here).

5) Is this an all-or-nothing affair, as in, if I do any testing at all, I should test everything? Or, is it a matter of any testing is better than no testing? If the latter, where are the more important areas to hit first (I'm thinking service layer)?

6) Are there any good books, articles, or sample apps that would help answer most of these questions for me?

I think that's enough for now. If this ends up being too open ended, let me know and I will gladly close. But again, I've already spent months trying to figure this out on my own with no luck.

Community
  • 1
  • 1
Jerad Rose
  • 14,405
  • 16
  • 78
  • 150

1 Answers1

5

This is really complex question. Each of your point is large enough to be a separate question so I will write only short summary:

  1. Integration testing and unit testing don't replace each other. You always needs both if you want to have well tested application. Unit test is for testing logic in isolation (usually with help of mocks, stubs, fakes, etc.) whereas integration test is for testing that your components work correctly together (= no mocks, stubs or fakes). When to use integration test and when to use unit test really depends on the code you are testing and on the development approach you are following (for example TDD).

  2. If your POCOs contains any logic you should write unit tests for them. Logic in your repositories is usually heavily dependent on database so mocking context and test them without database is usually useless so you should cover them with integration tests.

  3. It is really dependent on what you expect from repositories. If it is only stupid DbContext / DbSet wrapper then the value of repository is zero and it will most probably not make your code unit testable as described in some referenced debates. If it wraps queries (no LINQ-to-entites in upper layer), expose access to aggregate roots then the meaning of repository is correct separation of data access and exposing mockable interface.

  4. It is fully dependent on previous point. If you expose IQueryable or methods accepting Expression<Func<>> passed to IQueryable internally you cannot correctly mock the repository (well you can but you still need to pair each unit test with integration test testing the same logic). LINQ-to-entities is "side effect" / leaky abstraction. If you completely wrap the queries inside repository and use your own declarative query language (specification pattern) you can mock them.

  5. Any testing is better then no testing. Many methodologies expects high density coverage. TDD goes even to 100% test coverage because test is written always first and there is no logic without test. It is about the methodology you are following and up to your professional decision to chose if you need a test for piece of code.

  6. I don't think that there is any "read this and you will know how to do that". This is software engineering and software engineering is an art. There is no blue print which works in every case (neither in most cases).

Community
  • 1
  • 1
Ladislav Mrnka
  • 349,807
  • 56
  • 643
  • 654
  • Thanks, Ladislav. I know this isn't an easy question to answer, and I appreciate you taking a stab at it anyway. To clarify, I will likely have dumb repositories, and keep the LINQ-to-entities logic in my service layer. So it will really be putting a lot of responsibility (business + query logic) in my service layer. Can this lead to its own issues -- i.e. what are the tradeoffs to this vs. having a repository for my LINQ-to-entities logic and keeping my service layer to strictly business logic? Again, I know this is subjective, I'm just trying to make sure I understand the tradeoffs. – Jerad Rose Nov 09 '11 at 15:08
  • _As an off-topic side note, I wanted to thank you for your contribution to the SO community, and to my questions in particular, as you often seem to answer a lot of my questions, most of which seem to have required a lot of time and thought on your part. It doesn't go unappreciated._ – Jerad Rose Nov 09 '11 at 15:10