It's a special Obon holiday, but I don't feel like having a summer cold, so I poke Google Mock in my room. I'm using C for some reason at work, so I've summarized how to use Google Mock for C code. This time is the introduction.
It seems that there are many articles of this degree, so I will go straight to it. I think the following will also be helpful. https://qiita.com/shohirose/items/30e39949d8bf990b0462
Suppose you have code like this. (I omit Include, but I'm doing it well)
sub.c
#include "mystr.h"
int test1(const char* str)
{
fprintf(stderr, "test print %s\n", str);
return str_analyze(str, 10);
}
mystr.c
int str_analyze(const char* str, int max)
{
int l;
for (l = 0; l < max; l++) {
if (str[l] == '\0') break;
}
return l;
}
The code to test the return value of this test1 ()
function would be:
sub_test.cpp
TEST(sub_test, test01)
{
EXPECT_EQ(6, test1(": test"));
}
For the time being, these placements and builds are done as shown in the site below. https://techblog.kayac.com/google-test
g++ -std=c++11 test/sub_test.cpp -I. -Isrc -Igoogletest/include -Lgoogletest -lgtest -lgtest_main -lpthread
If you do this, the ʻa.out` file will be generated as a test program and you can run the test.
If this is left as it is, the source code and development code of Google Test will be fused, so try changing the arrangement as follows.
|
+- GoogleTest
| + ...
|
+- work
+ sub.c
+ sub.h
+ mystr.c
+ mystr.h
The build at this time can be done by slightly changing the command written above, but it is annoying. So I will use scons that I learned at work recently. I wrote it while looking at the following. [^ 2] https://scons.org/doc/0.97/HTML/scons-user/x628.html
SConstruct
env = Environment()
env.Program(
target='sub_test',
#You can debug with gdb if you don't have to add debug options
CCFLAGS = '-g',
source = [
"sub.c",
"mystr.c",
"sub_test.cpp",
],
LIBPATH = [
"../googletest/lib",
"../googletest/googlemock/lib",
],
LIBS = [
'libgtest.a',
'libgtest_main.a',
'libgmock.a',
'libgmock_main.a',
'pthread',
],
CPPPATH = [
'.',
'../googletest',
'../googletest/googletest',
'../googletest/googletest/include',
'../googletest/googlemock',
'../googletest/googlemock/include',
],
)
Well, this is not so good because the intermediate products are mixed in the source code, but this time it became annoying, so it is as it is.
The contents from here refer to the following page in addition to the official document.
The reason for using Mock is also explained in the translation of the official documentation.
http://opencv.jp/googlemockdocs/fordummies.html
In a normal program, you will use a real implementation of this interface. The test uses a mock implementation instead. This makes it easy to check which drawing primitives were called from the program, what the arguments are, and what the order is. Tests written this way are very robust (they don't break due to changes in machine antialiasing), are easy to decipher and maintain (the purpose of the test is expressed in code rather than in an image file). ), And the test execution is much faster.
Personally, I think that white-box testing checks such as whether they are called and the order are important for using Mock.
Now, let's create a Mock of str_analyze ()
as a module to Mock mystr. However, since Google Mock is for C ++, it cannot be used as it is for C.
It doesn't seem to be written on the official page, but it seems that you need to create an interface class [^ 3] to use Google Mock. So, mystr is C, but if it is C ++ ... I will create a header file.
mock/mock_mystr.h
class Mystr {
public:
Mystr(void){}
virtual ~Mystr(void){}
virtual int str_analyze(const char* str, int max) = 0;
};
Continue writing the corresponding Mock class.
mock/mock_mystr.h
class MockMystr : public Mystr {
public:
MockMystr(){}
~MockMystr(){}
MOCK_METHOD2(str_analyze,
int(const char* str, int max));
};
Of course, you can't call a C ++ class from C code, and it's not good to rewrite the code you're testing. Therefore, create a Mock as shown in Reference Page 2 above.
mock/mock_mystr.h
extern MockMystr* mystr_mock;
extern "C" int str_analyze(const char* str, int max)
{
int ret = mystr_mock->str_analyze(str, max);
return ret;
}
I think that ʻextern "C" `is generally necessary for suppressing mangling.
So far, I've almost created a Mock for the str_analyze ()
function that I wanted to make into a Mock, so I'll use this.
First, make the body of str_analyze ()
invisible.
SConstruct
source = [
"sub.c",
- "mystr.c",
+ #"mystr.c",
"sub_test.cpp",
],
Then add Mock references and settings to your test program.
sub_test.cpp
#include "mock/mock_mystr.h"
MockMystr* mystr_mock;
//It seems that such a Main function is necessary when using Mock
int main(int argc, char** argv)
{
::testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}
TEST(sub_test, test01)
{
mystr_mock = new MockMystr();
const char* test_str = ": test";
int test_str_len = strlen(test_str);
EXPECT_CALL(mystr_mock, str_analyze(_, _))
.WillOnce(::testing::Return(test_str_len));
I've also written an Expectation for calling Mock above. ʻEXPECT_CALL` is the one. Now you can test.
After introducing Google Test and arranging the layout a little, I made it possible to use Google Mock in C as well. There are several ways to use Google Mock in C, but this time I'm using C's Google Mock in the next step.
Creating an interface class and creating a Mock function is a hassle, but since each is a simple description, I think it could be automated.
For this time, when I was playing with Mock, I got the following build error and suffered for a while.
sub_test.o: In function `Mystr::Mystr()':
/var/work/c/test/work/./mystr.h:5: undefined reference to `vtable for Mystr'
sub_test.o: In function `Mystr::~Mystr()':
/var/work/c/test/work/./mystr.h:6: undefined reference to `vtable for Mystr'
Ah, yeah, I felt like vtable is the one I see from time to time. In my life so far, I've been playing around with it and this error has disappeared! I've spent time in Japan, but this time I was motivated to investigate. What is virtual? Or vtable? With that feeling. Then I finally arrived at the following page.
http://yukichanko.hatenablog.com/entry/20110113/1294932335
Well, this page is not the answer either, but in short, if you create a half-finished interface class as shown below, you will get an error like this.
class Mystr {
public:
Mystr(void){};
virtual ~Mystr(void){};
virtual int str_analyze(const char* str, int max); //Not a pure virtual function
};
I don't think I can conclude that the interface class is out of order by reading the g ++ error message as it is, but does this make sense?
I will publish it below. work01 has no mock and work02 has mock.
https://github.com/hakua-doublemoon/GoogleTestStudy
[^ 1]: I used Windows Docker for the first time this time, but I felt that I didn't need WSL if I had this. Performance may be different, but what you can do is not much different. Then I thought that Docker would be easier to manage. [^ 2]: Somehow SConstruct is the same as Make, and I can't find a cool way to write it ... [^ 3]: It wasn't until I came here that I somehow understood the interface class. I was a little convinced that it felt like a Rust trait. [^ 4]: It may be better to use a smart pointer as shown in the reference page, but this time I haven't used it.
Recommended Posts