Search code examples
c#tddsapb1

Test Driven Development with very large Mock


I am working for a consulting company that develops a lot of Add-Ons for SAP Business One using .NET. I want to introduce TDD (or at least some good unit testing practices) to the company to increase code quality. Here's the problem.

SAP provides a COM object (called Company) that lets you interact with the data in SAP. Company is an interface, so it can be mocked, but the amount of Mocking that would have to be done to get a single test to run is huge! I've tried it out with a few tests, and although they work, I really had to have a good understanding of the internals of the unit that I was testing, in order to create tests that passed. I feel that this very much defeats the purpose of the unit tests (I'm testing the internals as opposed to the interface).

Currently, through the use of dependency injection, I've created a Mock Company object that returns some Mock Documents that will sometimes return Mock values based on different circumstances, just to get the tests to run. Is there a better way? Has anyone been able to effectively unit test code that heavily depends on some external library? Especially when the results of the tests should be some change to that mocked object? (Say, when the add-on runs, the Mock Company object's SaveDocument function should be called with this Mock document).

I know this may be a strange question, but the fact of the matter is that in order to get these unit tests to run well, I feel like the only option to me is to create a really...really large mock that handles multiple Mock Documents, knows when to give the documents at the right time, and a lot of other things. It'd be essentially mocking out all of SAP. I don't know if there's some other best practice that others do in these cases.

Thanks in advance!

EDIT: Carl Manaster:

You're probably right. I think the problem is that most of the existing code base is very procedural. A lot of Windows services with a Run() method. I can definitely see how, if the project was structured a bit better, tests could be made with a lot more ease.

But let's say that the company can't invest in refactoring all of these existing projects. Should I just abandon the idea of unit testing these things?


Solution

  • If your methods are short enough, you should be able to mock only the interactions with one entity (Company), without interacting with the entities it returns. What you need is for your method to call (let's say) company.getDocument(). If your method under test has further interactions with the returned document at that point, split out that code, so that you can test that code's interactions with a (mocked) Document, without worrying about the Company in that test. It sounds as though your methods are currently much too long and involved for this kind of approach, but if you whittle away at them to the point where testing one method simply verifies that company.getDocument was called, you will find it much easier to test, much easier to work with, and ultimately much easier to understand.

    Update

    To your question of whether you should abandon the idea of unit testing: Do you want it to work? Do you have changes to make to the code? If the answers are (as I would assume) affirmative, then you should probably persevere. You don't have to test everything - but test what you're changing. You don't have to refactor everything - but refactor what you're working on so it's easier to test and easier to change. That "whittling away" that I mentioned: do that in service of solving the problems you have at the moment with your code base; over time you will find the code that most needed the tests has been tested - and it's a lot easier to work with because it's well tested and better factored.