Posts tagged Unit Testing
Every once and a while I get a fair amount of flak about how I unit test my services. I’m a firm believer in the Onion Architecture and Repository Patterns and the techniques developed at Online Advisors for implementing those patterns are still better then any other implementation I’ve seen.
The repository itself is generic and thin. You can see an implementation on this GitHub page. With the underlying data store implementation hidden behind a generic interface that makes it very easy to mock the calls to the database, but should you?
Any Unit Testing purist will tell you that Unit Testing is only testing one small, isolated, functional unit of code. When that unit of code go out of scope it needs to be mocked. This is all well and good, and I do a fair amount of testing like this. But then Entity Framework Code First and automatic migrations came along, coupled with SQLCE or LocalDB why mock your repository?
When my repository method is generic (i.e. a Get, Save, Delete) there is no real logic in there. But when I test it I gain the added benefit of verify that data going to the database and back is correct. Additionally using the Seed method of Entity Framework it’s very easy to scaffold in test data that can be utilized by the test.
Anyone who’s mocked complex data structures knows your basically writing a lot of that by hand, or storing it in a file and deserializing it to be served up to tests. If your going though that trouble, then why not just use EF, Code First, Automatic Migrations and Seeding? It really is a time saving once you got the data in the seed statement.
Additionally it’s helped me find concurrency and data access issues. Because of how unit tests are executed using a lightweight SQL instance I was trace down race conditions and slow LINQ statements. None of which would have been possible by just testing the service or logic layer in isolation.
When I test this way I still call it unit testing. The way it gets the data, either through an In-Memory array, Mock or LocalDB is not what’s being tested. As long as my repository method itself has no code or logic it will be side effect free.
This isn’t without it’s faults and it’s not perfect. Based on their very nature SQLCE and LocalDB are very lightweight version of SQL Server. This means they can’t perform the way normal SQL does, operate in the same way or even use some of the same data types. For example SQLCE doesn’t support the Geo data type.
So it may not be perfect for every scenario or database. But if it’s an option, will be side effect free and won’t cause interdependency issues between tests then really is the difference between that and Mocking? Besides the fact that your exercising more of your code base?
Resgrid is a SaaS product utilizing Microsoft Azure, providing logistics, management and communication tools to first responder organizations like volunteer fire departments, career fire departments, EMS, search and rescue, CERT, public safety, disaster relief organizations, etc. It was founded in late 2012 by myself and Jason Jarrett (staxmanade).
On Friday a blog post from Joel Spolsky hit Slashdot. This post from Joel was a good read and centered around using programmers who, “Just get the job done”, or as Joel referred to them as Duct Tape Programmers. The gist of the post centered around not worrying about n layers of abstraction to complete a simple task, but to code it and ship it. It’s a good read and I recommend it. Uncle Bob also posted a rebuttal, which is a good read as well.
I like the feeling behind Joel’s post and I probably would consider myself a Duct Tape Programmer, but I don’t think I’m good looking enough. But I think Joel is just a little left of center with his post and it misses the mark on what we should be communicating to our fellow developers. I believe the message to developers should be that of moderation and not out right not doing.
Is an application with three layers of abstraction better then an application with none? Can you honestly answer that question? Does loosely coupling your application make it better then one that is tightly coupled? If you answered yes to that then your missing the whole point of software development. Software development is an art form and the patterns and practices that we employ in our field don’t always apply to every software application we build. Every piece of software we code is in a vacuum, and we need to apply the best tools for the job to complete the job well.
What I got out of Uncle Bob’s article is that I can develop bad applications without ‘complex’ tools like multi-threading and abstraction just as easily as I can with them. Just because I have to tool in my toolbox doesn’t make me included to use it, and we should be forced to. I’ve build some small tightly coupled applications that work great and haven’t failed or stopped working in years, does that make them bad?
There are some universal truths in our field though. I’m not a huge Unit Testing fan and I think people can go way overboard with it. But having some unit tests that exercise your code business logic is never a bad thing. But in crunch time will I cut unit tests or functionality? Probably unit tests, sorry boys and girls but unit tests aren’t a deliverable the vast majority of the time. But does that mean it’s ok never to do them just because they may be the first to be cut? No, never, never. I’m not a fan of TDD but it can be extremely useful and it just another tool in the box, like paired development.
I don’t think Joel is calling all non Duct Tape Developers stupid, but I think entering into a project with a rigid set of tools and patterns is, and so is the reverse. Don’t empty your tool box because you don’t like TDD or Unit Tests, but try to use them from time to time. Also don’t try and apply TDD and 100% code covered to an application that just emits “Hello World” to the console. Yes a lame example I know.
If you never try those things how will you know if they work? If you never try multi-threading and application or writing a few layers of abstraction can you expect to correctly identify where they will come in useful and how they will be useful? If you never tried TDD can you determine where and why it’s useful? Fill your toolbox with great tools, like Duct Table, but always remember to draw up a blue print to use them correctly.
“Memento Audere Semper” Remember Always to Dare.