Writing tests for code that uses a random number generator (RNG) can be tricky, as random behavior introduces non-determinism into your tests. However, you can make testing easier by controlling or "mocking" the randomness. There are several strategies you can use to test code that involves random numbers, particularly when using a testing framework like Google Test.
Here are the steps to test code that uses a random number generator:
1. Refactor to Allow Injecting the RNG
If possible, refactor your code to allow the random number generator to be injected (dependency injection). This allows you to substitute the random number generator with a mock or predictable RNG during testing.
Example Code to Refactor:
In this refactored code, RandomGenerator
is an abstract class that is implemented by RealRandomGenerator
. The MyClass
class takes a pointer to a RandomGenerator
in its constructor, allowing you to inject different implementations for testing purposes.
2. Write Google Test for Injected RNG
Now, you can write a test that uses a mock RNG. In Google Test, you can use Google Mock to create a mock class for RandomGenerator
that returns predictable values.
Step-by-Step Google Test Example:
Key Elements of the Test:
-
MockRandomGenerator: The mock class simulates the behavior of the
RandomGenerator
. We use Google Mock'sMOCK_METHOD
macro to create the mock methodgenerate()
. -
EXPECT_CALL: We use
EXPECT_CALL
to specify that thegenerate()
method should be called, and we useWillOnce(testing::Return(value))
to define what value it should return when called. -
Testing: After injecting the mock into the class, we test the behavior of the
MyClass
methods. We verify that the correct value is returned when the random number is generated, allowing us to validate the logic without involving true randomness.
3. Test with Real RNG (Optional)
If you want to test the real random number generator as well, you can do so by controlling the seed or by using a known seed value in the random generator.
In this test, we’re not testing for a specific random number (since it's truly random), but we can verify that the generated value falls within the expected range (1 to 100 in this case).
4. Use a Fixed Seed for Predictability
If you want to make the tests more deterministic but still use a real RNG, you can fix the random number generator's seed to a known value. This way, the sequence of random numbers generated will always be the same across runs.
5. Testing Edge Cases
You can test edge cases like generating the minimum or maximum possible random values:
Summary:
To effectively test code that involves randomness:
- Refactor your code to allow dependency injection of the RNG.
- Use Google Mock to mock or control the behavior of the RNG.
- You can use a fixed seed for reproducible tests.
- Validate that your code behaves correctly even with predictable/random values within expected ranges.
By following these strategies, you can create reliable and deterministic tests for code that involves random number generation.
No comments:
Post a Comment