A Pragmatic approach to Unittesting a class' Internals

A Pragmatic approach to Unittesting a class' Internals

When you drive your car, and you want to slow down, you hit the brake pedal. Under the pedal is a myriad of quite advanced systems, but as a driver all that technology is abstracted away from you by the car manufacturer so you can focus your attention on the traffic.

When I take my car to the yearly technical inspection, that changes. Now it's no longer sufficient if hitting the brake slows down the car, instead the test bank will check if all of the four wheels individually have the right amount of braking power, and that there is no substantial unbalance between all wheels.

It's an example of how using an object can be different for the typical end user (the car driver) and the unit tester (the car technician)

Let's translate the example above to a simple software example: a command-line parser. You enter a line of text, and it executes the command with the right arguments.

We need several helper-functions under the hood: to count the number of arguments, split the textline into separate tokens, recognize and validate the commands and their parameters. All of these helpers can be hidden from the end-user. Still, to decently test the parser, it would be great to test them in isolation, simply because isolating them, will drastically reduce the number of test-cases and makes each test simpler.

I have been hitting this dilemma too often, and did a lot of research to find a solution. Most unit-testing guru's simply declare that you only test the public interface, and that you don't care about the internals. Well, I disagree, and I hope that the examples above made it clear why. A more pragmatic approach is needed.

Here's my proposal :

* put your public: on top of the class (this is best practice anyway)

* put you private: at the bottom

* put a second private: section in the middle, with all internals you want hidden from the end user, but visible for the tests.

With a simple #ifndef unitTesting, this keyword will be outcommented when the compiler compiles for a unit test build.

class commandLineParser {
    public:
        void parseAndExecute(const char* lineOfText);

#ifndef unitTesting
    private:
#endif

        int numberOfArguments(const char* lineOfText);
        void getToken(char* output, const char* input, int tokenIndex);

  private:
        ...
};        

Like or disagree, or maybe have a better solution ? Feel free to leave a comment.

要查看或添加评论,请登录

Pascal Roobrouck的更多文章

  • How to cover legacy code with unit tests

    How to cover legacy code with unit tests

    In one of my firmware projects, I needed to display QR Codes onto a display. I found reasonably good code which I could…

  • Applying Solder Paste for PCB Prototyping

    Applying Solder Paste for PCB Prototyping

    During prototyping, I have the habit of assembling a few PCBs myself. This has several benefits, such as: it's possible…

    1 条评论
  • LoRaWAN encryption in Hardware

    LoRaWAN encryption in Hardware

    Isn't it sad that hardware engineers build all those powerful features into modern microcontrollers, and then the…

    1 条评论
  • Make something with your children - lessons learned

    Make something with your children - lessons learned

    This summer, my youngest son asked me to build a piece of furniture together. Doing so, I learned a few surprising…

    7 条评论
  • Prik van AFAS

    Prik van AFAS

    Begin alvast maar te sparen voor een Audi e-tron, een Volvo Plugin-Hybrid of die droom van een Tesla. Ga je bij AFAS op…

    1 条评论

社区洞察

其他会员也浏览了