# Mocksmith

Mocksmith is a command line utility and a Rust library to automatically generate C++ mock
classes and header files for the [Google Mock](https://google.github.io/googletest/gmock_for_dummies.html)
(gMock) framework, part of [Google Test](https://github.com/google/googletest). This
documentation mainly focuses on the command line program.
## Installation
Mocksmith uses libclang to parse the source C++ code provided to it, so you need to
install clang first. On Linux, you typically install clang with your package manager,
e.g., `apt` in Debian-based distributions like Ubuntu:
```shell
$ sudo apt install clang
```
For Windows, you can find binaries to install [here](https://github.com/llvm/llvm-project/releases),
e.g., [LLVM-20.1.7](https://github.com/llvm/llvm-project/releases/download/llvmorg-20.1.7/LLVM-20.1.7-win64.exe).
Make sure to add the LLVM bin folder to your `PATH` environment variable, which is an
option when installing, otherwise Mocksmith will not be able to find libclang.
When you have libclang in place, you can install the `mocksmith` program with cargo:
```shell
$ cargo install mocksmith
```
Currently, no pre-built binaries for `mocksmith` are distributed.
## Usage
To generate mocks to stdout, just pass paths to files with classes to mock as arguments to
`mocksmith`.
```shell
$ cat IMyItem.h
#pragma once
#include <string>
class IMyItem {
virtual ~IMyItem() = default;
virtual int do_stuff(const std::string& text) = 0;
};
$ mocksmith IMyItem.h
class MockMyItem : public IMyItem
{
public:
MOCK_METHOD(int, do_stuff, (const std::string & text), (override));
};
```
### Generate Header Files
To generate a complete header file, you pass an option with the name of the header file.
With this option, a single header file is generated, with all mocks for classes from all
source files.
```shell
$ mocksmith -o MockMyItem.h IMyItem.h
$ cat MockMyItem.h
// Automatically generated by Mocksmith
#pragma once
#include "IMyItem.h"
#include <gmock/gmock.h>
class MockMyItem : public IMyItem
{
public:
MOCK_METHOD(int, do_stuff, (const std::string & text), (override));
};
```
If you prefer to create one header file per source file, pass an option with the
output directory instead.
```shell
$ mocksmith -d . IMyItem.h
$ ls MockMyItem.h
MockMyItem.h
```
Note that `mocksmith` does not overwrite existing files if the content would not change.
This is useful to avoid triggering rebuilds of code which includes the mock header file,
if the build system depends on file timestamps.
### Naming Mocks
If you don't like the way `mocksmith` names the mock classes, you can use a regex-based
approach, similar to how `sed` works. The input to the regex part is the name of the
class to mock.
```shell
$ mocksmith -n "s/I(.*)/Fake\1/" IMyItem.h
class FakeMyItem : public IMyItem
[...]
```
### Naming Output Files
The output files in an output directory can be named similarly to the way mocks can be
named.
```shell
$ mocksmith -d . -f "s/I(.*).h/Fake\1.hpp/" IMyItem.h
$ ls FakeMyItem.hpp
FakeMyItem.hpp
```
### Include Paths
Most of the time, you will have to tell `mocksmith` include search paths with the `-I`
option, similar to compilers like clang and gcc. If clang can't locate an included header,
`mocksmith` will stop and report an error.
Let's say we have a directory structure like this:
```shell
$ tree code/
code/
|-- itemcomponent
`-- subcomponent
`-- MyEnum.h
$ cat code/itemcomponent/IMyItem.h
#pragma once
#include "subcomponent/MyEnum.h"
class IMyItem {
virtual ~IMyItem() = default;
virtual void do_stuff(MyEnum) = 0;
};
$ cat code/subcomponent/MyEnum.h
#pragma once
enum class MyEnum { One=1, Two=2 };
```
If you use `mocksmith` without include search paths to locate included headers, you get an
error.
```shell
$ mocksmith code/itemcomponent/IMyItem.h
Error: Could not create mocks for file code/itemcomponent/IMyItem.h
Caused by:
Parse error in file code/itemcomponent/IMyItem.h at line 2, column 10: 'subcomponent/MyEnum.h' file not found
```
Adding `-I code/` solves this:
```shell
$ mocksmith -I code/ code/itemcomponent/IMyItem.h
class MockMyItem : public IMyItem
{
public:
MOCK_METHOD(void, do_stuff, (MyEnum), (override));
};
```
The specified include search paths are also used to decide how to include the header file
of the source class when generating header files with mocks. The shortest relative path
from the given include search paths is used.
```shell
$ mocksmith -I code -d code/itemcomponent/mocks/ code/itemcomponent/IMyItem.h
$ cat code/itemcomponent/mocks/MockMyItem.h
// Automatically generated by Mocksmith
#pragma once
#include "itemcomponent/IMyItem.h"
#include <gmock/gmock.h>
[...]
```
It is possible to ignore errors from libclang with the `--ignore-errors` option but it is
not recommended since clang will report unknown types as `int`. It also fails to identify
methods as virtual when returning unknown types. Errors will still be logged, unless the
`--silent` option is used.
### Additional Options
See the help text, using the `-h` or `--help` option, for a complete list of options.
## Limitations
You should have LLVM/Clang 19 or newer. Intermittent problems have been seen when
executing tests using Clang 18.x, indicating possible issues when using the program.
On Windows, there is a [bug](https://github.com/KyleMayes/clang-rs/issues/63) in the
underlying clang-rs Rust wrapper library which makes it impossible to use the "runtime"
feature. Thus, libclang must be in the `PATH` since it cannot be located at runtime
automatically.
If you have problems with Mocksmith not finding your libclang installation, consult the
clang-sys [documentation](https://github.com/KyleMayes/clang-sys#dependencies).
## Alternatives
Up until, and including, Google Test 1.11.0, there was a Python script included with
Google Mock to generate mocks. The script was based on a simple C++ parser written in
Python which had problems with modern constructs and advanced features of C++.