2

I am working on a legacy code base and I need to find a way to write unit tests for this project.

The project has a three layer architecture (UI-Biz-DAL as we call them) and DAL is totally implemented using ADO.Net and Typed-Datasets and it is full of SQL Scripts.

Our Biz classes have methods that are responsible for doing business logic stuffs and they are dependent on other helper classes and DAL classes.

I know I can use DI to inject these classes to my Biz classes but I think that I should change a lot of code. Here's a solution that I can think of :

There's this TestContext class that acts as a container and can contain mock objects for tests but it does not have anything when it comes to run the actual code so that real objects can be used instead , here is an example :

var dal=TestContext.Current.Resolve<IMyDAL>(@default:new MyDal());

as you can see Resolve method accepts an argument of type IMyDAL that will be used in case of not running our tests.

First I would like to know what do you think about this solution

Second I am still thinking about a way to test SQL scripts that are hardcoded in our code base . How can I test them ?

  • 1
    You can test pretty much anything. With some monkey patching you can even test the hated static methods. The thing is testing code following DI is so much more easier than any other way. – Andy Jan 3 '16 at 7:07
  • What do you mean by monkey patching ? (and yes those static methods are really hated ;) ) – Beatles1692 Jan 3 '16 at 7:10
  • Basically changing code during runtime to provide stubs for the static methods instead of using the real ones. – Andy Jan 3 '16 at 7:16
  • Well as far as I searched monkey patching is not possible in C# unless we use a unit testing framework such as TypeMock. – Beatles1692 Jan 3 '16 at 7:26
1

What you're suggesting is homebrewed DI tightly coupled to each business object and auto-wiring the current behavior.

Just. no. Use a real DI solution, and auto-wire THAT to the legacy DAL.

Change the code. You're writing tests here, man, that's the Lord's work.

  • I agree with you to some extent but It involves a lot of change in our code and I am afraid that it can make people anxious :) – Beatles1692 Jan 3 '16 at 7:19
  • If you do your job right you'll be preventing anxiety for years to come. I think what you're proposing is an equivalent level of code change, and what's more because it is tightly coupled it fails to achieve the goal of DI -- which is the binding of code objects to independent interfaces rather than tightly coupling concretions to each other. – Matthew Mark Miller Jan 3 '16 at 7:30
  • I couldn't agree more. Actually I am suggesting this TestContext object as a temporary solution so we can have our code refactored without having to add a IoC container in the first place.When everything is in place we can remove TestContext and replace it with a real IoC container. – Beatles1692 Jan 3 '16 at 7:39
  • Instead of using an IoC container can we use a default ctor that calls the injection ctor with concrete objects ? – Beatles1692 Jan 3 '16 at 8:03
  • Ugh, I dunno man, anything you do the concretions short of introducing IoC is going to increase the total amount of effort. Have you thought about simply introducing assembly or package local mutators for the services you want to inject, something that would obviously only be for testing? – Matthew Mark Miller Jan 3 '16 at 8:19
1

Depending on your version of studio you can use Microsoft Fakes, in particular shims to be able to mock most things - https://msdn.microsoft.com/en-us/library/hh549176.aspx .

Once your library is covered with tests you can have these as a safety net while you introduce proper DI and fully isolated tests.

The danger is that shims are evil and can let developers get away with bad practice.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.