How to write Unit Tests for functions that rely on dynamic data?

Jake Wilson picture Jake Wilson · Apr 23, 2012 · Viewed 7.1k times · Source

Lets say you have a website, that uses a function to retrieve data from the database and returns the result to be displayed/parsed/etc...

Since the data that is retrieved from the database is dynamic and could potentially change every second of the day, how do you properly write a Unit Test for this function?

Let's say the function is supposed to return an array of results. Obviously a unit test could test to see if an array is returned or not. But what happens when the contents of the array itself are incorrect due to an incorrectly written MySQL query? The size of the array could be zero or the content of the array could be incorrect. Since it relies on ever-changing data, how would the Unit Test know what is correct and what isn't? Would calls to the database from within the Unit Test itself be necessary so there is something to compare it to?

How do you properly write a Unit Test for functions that rely on dynamic data?

Answer

Ben Taitelbaum picture Ben Taitelbaum · Apr 23, 2012

Unit tests, in their ideal form, should only test one thing. In this case, you're testing two things:

  1. the logic of your function
  2. the database retrieval

So I would suggest the following refactor:

  1. Move the database retrieval logic into a separate function
  2. Have the function you want to test call that other function
  3. Mock out the function that returns data so you can unit test just the logic of your app
  4. If it makes sense (if you're just relying on another library to do this, then hopefully that lib already has tests), write a unit test for the dynamic retrieval function, where you can't test specifics, but can can test the structure and reasonableness of the data returned (e.g. it has all the fields set, and is a time within 5 seconds of now).

Also, typically it's a good idea to run unit tests in a test environment where you have complete control over what's stored in the database. You don't want to run these against production data.