1

I am implementing an ECS system with a data-oriented design, and with a TDD methodology using Catch 2. I have the following class declaration snippet for an EntityManager:

using Entity = std::uint16_t;
using Signature = std::bitset<MAX_NUM_COMPONENTS>;

const std::uint16_t MAX_NUM_ENTITIES = 10000;

class EntityManager
{
public:
  ...
  Entity createEntity();
  ...
private:
  Signature entities[MAX_NUM_ENTITIES];
  ...
}

The purpose of EntityManager::createEntity() is to simply return an Entity (which we will refer to as e), and set entities[e] to some value. However, the method must throw an exception when the number of entities that exists are more than MAX_NUM_ENTITIES.

I would like to unit test the aforementioned method. But, I am unsure how to do so. An idea I have is to fill up the entire entities array by calling createEntity() MAX_NUM_ENTITIES + 1 times in my test to trigger an exception. However, I have a feeling that it is not the best way to do it, and may even result in a slow test run. Another idea, but similar to the previous one, is to somehow mock entities so that it would have a small size. We will then call createEntity() multiple times until an exception is raised just like the previous idea.

What approach would you recommend?

8
  • I would call the test in a try/catch and put an explicit failure after the call within the try block. The catch can either test the content of the exception or simply it's presence is the pass case. That's what languages like Java and C# did before they had lambdas or annotations. Works well. Commented Feb 23, 2020 at 3:37
  • @BerinLoritsch, thanks for that suggestion. But, the method should only throw an exception when it has been called more than 10,000 (actually MAX_NUM_ENTITIES, but we'll use its actual value instead for simplicity) times (without any prior entity deletions). Would it be wise to call the method inside the try/catch block 10,001 times just for the method to throw an exception? Or is there a better way? Commented Feb 23, 2020 at 5:00
  • 6
    I'd consider changing MAX_NUM_ENTITIES from a const to a constructor parameter, perhaps with a default value. For your unit test pass a tiny number.
    – user949300
    Commented Feb 23, 2020 at 8:59
  • 2
    How regularly is createEntity() expected to change? If the answer is never or hardly ever, consider manual testing. For a stable piece of code an automated test that runs all the time doesn’t provide a lot of value, especially if the test is expensive (in runtime or increased test implementation complexity because of a mock).
    – besc
    Commented Feb 23, 2020 at 9:04
  • 4
    We had a similar problem in our company. We couldnt (didnt want to) move MAX_NUM_ENTITIES to a constructor argument, because then it would be fixed at runtime and not at compile time. Our solution was to move it to a template parameter and add a typedef for the original size: using DefaultEntityManager = EntityManager<10000>. This way, the unit tests could use EntityManager<10>. Would this work in your case?
    – pschill
    Commented Feb 23, 2020 at 9:41

1 Answer 1

4

how would one unit test a method that must throw an exception when a private array no longer has “space”?

Reverse the question: how would you design a method that would support testing it?

You'd probably arrange things so that your test could control the size of the buffer, so that you can set it to something simple to test, like 1 or 2. You might also have methods that allow your test to inspect what is going on.

Replacing "designs that are hard to test" with "designs that are easy to test" is an important motivator for .

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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