Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking system calls - is there better way? [duplicate]

We are now introducing unit tests in our company and thinking about best way of mocking system calls.

Consider the following code

    int fd = open(path, O_RDONLY);
    if (fd < 0) {
        LOG.error() << "cannot load plugin " << path << std::endl;
        return ERROR(ERROR_OPENING_PLUGING);
    }
    // do other stuff

Obviously, we need to mock system call to open

I have found following ways to do so:

  1. Correct - in the terms of design but ugly way. Create interface and impl

    class ISystem
    {
    public:
        typedef std::auto_ptr<ISystem> Ptr;
    
        ISystem() {};
        virtual ~ISystem() {};
    
        virtual int open(const char* file, int path) = 0;
    };
    
    class System : public ISystem
    {
    public:
        System() {};
        virtual ~System() {};
    
        virtual int open(const char* file, int path);
    
        static ISystem::Ptr Get();
    };
    

and use it

    Common::Error dlopen_signed(ISystem::Ptr& system, const char* path, int flags, void*& ret)
    {
    int fd = system->open(path, O_RDONLY);
    if (fd < 0) {
        LOG.error() << "cannot load plugin " << path << std::endl;
        return ERROR(ERROR_OPENING_PLUGING);
    }
    char fd_path[32];

I dont like it because every function will need to have one more argument - ISystem::Ptr& system, that will be the same for all production code.

Also, not sure about speed (this involves extra layers for basic system calls that must be really fast)

2) Use a link seam Linker is designed so that it prefer your versions of functions than system ones.

But this does not work for some system calls, for example open (not sure about the reason), and this solution is a little bit hackish.

3) use --wrap compiler functionality

--wrap symbol Use a wrapper function for symbol. Any undefined reference to symbol will be resolved to __wrap_symbol. Any undefined reference to __real_symbol will be resolved to symbol. This can be used to provide a wrapper for a system function. The wrapper function should be called __wrap_symbol. If it wishes to call the system function, it should call __real_symbol. Here is a trivial example:

void *
__wrap_malloc (int c)
{
  printf ("malloc called with %ld\n", c);
  return __real_malloc (c);
} 

This solution is nice but does not work for all compilers I guess.

The question is - which one are you using on your projects?

like image 817
Georgy Buranov Avatar asked Nov 27 '25 16:11

Georgy Buranov


1 Answers

You have to draw a line to what to mock, and what to unit test. 100% unit tests coverage is not the ultimate goal.

If you really want to mock systam calls, the best is to put them in a wrapper (the first option in the question). Not one huge wrapper, but you should split them into several wrappers by functionality.

like image 187
BЈовић Avatar answered Nov 30 '25 05:11

BЈовић



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!