Search code examples
c++googletestgooglemock

Mocking standard library functions using gmock


Following is the function which I want to unit test:

void sampleFunc()
{
   FILE *file = fopen(path, "rb");
   if (!file) {
     std::cout << "File couldn't be opened!" << std::endl;
   }
   const int bufSize = 32768;                                              
   unsigned char *buffer = (unsigned char*) malloc(bufSize);               
                                                    
   if (!buffer) {                                                           
     fclose(file);                                                       
     std::cout << "Failed to allocate buffer for SHA256 computation." << std::endl;
   }
   // ..
   // Read file into buffer
   // ..
}

As shown in the code, my function uses many standard library functions. So am I supposed to mock standard library functions or make actual calls to functions?


Solution

  • What you might do to test your function:

    class IFileManager
    {
    public:
        virtual ~IFileManager() = default;
    
        // You could even improve interface by returning RAII object
        virtual FILE* fopen(const char* path, const char* mode) = 0;
        virtual void fclose(FILE*) = 0;
        // ...
    };
    
    class FileManager : public IFileManager
    {
    public:
        FILE* fopen(const char* path, const char* mode) override { return ::fopen(path, mode); }
        int fclose(FILE* f) override { return ::fclose(f); }
        // ...
    };
    
    class IAllocator
    {
    public:
        virtual ~IAllocator() = default;
    
        virtual void* allocate(std::size_t) = 0;
        virtual void deallocate(void*) = 0;
    };
    
    class Allocator : public IAllocator
    {
    public:
        void* allocate(std::size_t size) override { return malloc(size); }
        void deallocate(void* p) override { free(p); }
    };
    

    Your function becomes:

    void sampleFunc(IFileManager& fileManager, IAllocator& allocator)
    {
       FILE *file = fileManager.fopen(path, "rb");
       if(!file) {
         std::cout << "File couldn't be opened!" << endl;
         return;
       }
       const int bufSize = 32768;
       unsigned char *buffer = (unsigned char*) allocator.allocate(bufSize);
    
       if(!buffer) {
         fileManager.fclose(file);
         std::cout << "Failed to allocate buffer for SHA256 computation." << std::endl;
         return;
       }
       // Read file into buffer
       // ...
    }
    

    Finally, you can easily mock IFileManager and IAllocator.

    Without that interface, you would have to make standard function behave as you expect, which is not necessary simple feasible (wrong path, limit memory (which limit))

    Care also that implementation might have more limitations. that the one from interface (MAX_PATH, non-regular files, UNC path)