2

I understand that you're not actually supposed to hit the database or disk when doing unit tests... Why is that?

Also, taking something like Moq, what is it actually supposed to mock and where? For example, let's say I want to create a method called "loadconfig" that loads an XML document. This would be a void method, so I would check that it has worked by writing tests around the get/set value methods...

So is Moq supposed to mimick a file being loaded? And I'm also to mock returning/setting values? I can see that Moq has assert methods, should these be used in the test method (seems unlikely since the document is stored in a private property)? If its supposed to be used in the get/set methods, then they must return a Boolean instead of the actual value - which means at some point the whole method would need to be changed?

Lastly, at some point you would surely need to remove all the Moq stuff and replace it with a real implementation? But then doesn't that mean the unit tests couldn't or shouldn't be used?

gnat
  • 21,442
  • 29
  • 112
  • 288
binks
  • 169
  • 3
  • For file and database IO, if you really want to test that, you can have a "test" database, like the one ruby on rails generates for you. Otherwise I would mock calls to 3rd party webservices and such while testing, returning a fixed answer from a fake server-talking class. Anyway you mock dependencys, not the actual unit you are testing. – SparK Nov 13 '14 at 15:29
  • se also: [When should I use mock objects?](http://programmers.stackexchange.com/questions/39378/when-should-i-use-mock-objects) – gnat Nov 13 '14 at 16:01

3 Answers3

7
  1. Because hitting a database is slow, requires an elaborate environment set up just right in order to work, and spends most time in code not written by you. A unit test is supposed to test your code, not Oracle's code.

2./3. No, you don't replace mocked things with real things. You leave mocked collaborators in your testing code, and then you don't ship your test code to the customer. You only ship your business code.

It can seem like a horrible waste at first to have huge amounts of code that aren't even delivered to anyone, but it isn't. Trust me. The point of testing is to improve the quality of business code, and a large, well-maintained test suite achieves exactly that, even though it never sees the light of day. Think of it as part of your tool set rather than part of the product - a baker sells bagels, he doesn't sell his oven.

Kilian Foth
  • 107,706
  • 45
  • 295
  • 310
5

When you are testing a unit of code (say a single method or class), you want to only test that unit and have no other dependencies (with possibly unknown state).

If you don't use mocks in unit tests, you are putting yourself in a position of uncertainty - if a class your method/class depends on changes, it can break your test even though your code has not changed.

This is particularly true for tests that depend on IO (disk, network, DB), as they may fail for reasons that have nothing to do with software - latency increases, network congestion, changes to the data in the database...

Again - unit tests are about testing a unit. In isolation.

Lastly, at some point you would surely need to remove all the Moq stuff and replace it with a real implementation?

Um. No. Not in you unit tests. Sure, in your actual codebase, where you use the class/method, you will pass it its actual dependencies, but in your test code? Always use the mocks.


Now for the implementation question:

If its supposed to be used in the get/set methods, then they must return a Boolean instead of the actual value - which means at some point the whole method would need to be changed??

Huh? If you are going to test via get/set methods, make sure they return what they should. In your test, your asserts are checking that what's returned is correct - not that what's returned is a boolean.

Oded
  • 53,326
  • 19
  • 166
  • 181
1

What's the idea behind mocking data access in unit tests ?

-

The speed of tests.

It's certainly true that you don't need to test the database, file system or other external dependency, but in reality it's often not that hard to set up the database, etc. and the actually code works aginst it so it's really easy to just use the database and it is closest to the real world.
Writing a whole of bunch of tests that have mocking and stubbing just to test 'only your code' with a separation of concerns is a high principle but not one that generally justifies the expense of actually doing it.

Except for one little thing.

Speed.

-

There is also another key component to consider in this area:

Integration Tests

These tests, for example browser ui automated tests really do test the whole stack and so they are great at making sure that, with real database connections, the application DOES really work as desired.

Using Integration tests is a key component in being comfortable about mocking and stubbing in unit tests.

Tests - hundreds and thousands of them - that access the database will be slow. For example, in the framework I know best - Ruby on Rails - a test that creates and uses several database objects (through active record) may take several thousand milliseconds. The code under test though may itself may take less than 100 milliseconds. Ultimately this can lead to test suites that take hours instead of minutes or seconds. A fast running test suite is key for modern rapid agile development and so this factor is key.

Smoke / Volume / Performance Tests

There may also be smoke tests, volume tests and performance tests that also exercise the full stack and provide coverage for mocking and stubbing in unit tests.

Michael Durrant
  • 13,101
  • 5
  • 34
  • 60