单元测试:生产代码和模拟实现的共存
Unit tests : cohabitation of the production-code and the mocked implementation
我知道有关测试替身、模拟等的基础知识,但我在测试以下内容时遇到问题
void funA(void) {
/* do some stuff, using mocked functions from 3rd party library */
}
我已经为 funA()
编写了单元测试,检查调用了好的函数(使用它们的模拟实现)。
到目前为止,模拟函数是库函数。这不是我的代码。我不想测试他们的原始实现。
现在,我想测试一下这个功能
void funB(void) {
/* do some complicated stuff, and call `funA()` on some situations */
}
如何确定我的 funA
函数是从 funB
调用的?我无法向 funA
添加伪造的实现,我需要它的生产代码以便对其进行测试。
我现在正在做的是确保 funA
调用的模拟与我期望的一样。但这不是一个好方法,因为这就像我在重新测试 funA
,而我只是想确保 funB
完成它的工作。
经过讨论(见原题评论),并与James Grenning(CppUTest的作者之一)进行了简短的论坛交流,主要解决方案如下:
funA()
和 funB()
有不同的测试版本
- 使用函数指针动态改变行为
我不是这两种解决方案的忠实拥护者,但感觉我不能在 C 中做更多事情。我最终会选择多二进制解决方案。
作为参考,这里是 James Grennings 的回答:
You may want to mock A() when testing B().
for example
If I have a message_dispatcher() that reads a command from a serial
port via getline(), and getline() uses getc() and getc() uses IORead
and IOWrite. I could mock IORead and IOWrite and have a set of
horrible tests to test the message_dispatcher().
Or I could test getc() with mock IORead() and IOWrite(), getline()
with some kind of fake_getc(), and test message_dispatcher() with
fake_getline(). If you only use linker substitution, you would need
three tests builds. If you used function pointers you could do one
test build. You can mix an match too.
getc() should be tested with link time mocks of IORead and IOWrite
because your unit tests never want the real IORead and IOWrite for
off-target tests (they may be needed of on-target tests, but those
would be integration tests).
There are many possibilities. You could also have some other code
getline() and feed it to the dispatcher, removing its dependencies.
我知道有关测试替身、模拟等的基础知识,但我在测试以下内容时遇到问题
void funA(void) {
/* do some stuff, using mocked functions from 3rd party library */
}
我已经为 funA()
编写了单元测试,检查调用了好的函数(使用它们的模拟实现)。
到目前为止,模拟函数是库函数。这不是我的代码。我不想测试他们的原始实现。
现在,我想测试一下这个功能
void funB(void) {
/* do some complicated stuff, and call `funA()` on some situations */
}
如何确定我的 funA
函数是从 funB
调用的?我无法向 funA
添加伪造的实现,我需要它的生产代码以便对其进行测试。
我现在正在做的是确保 funA
调用的模拟与我期望的一样。但这不是一个好方法,因为这就像我在重新测试 funA
,而我只是想确保 funB
完成它的工作。
经过讨论(见原题评论),并与James Grenning(CppUTest的作者之一)进行了简短的论坛交流,主要解决方案如下:
funA()
和funB()
有不同的测试版本
- 使用函数指针动态改变行为
我不是这两种解决方案的忠实拥护者,但感觉我不能在 C 中做更多事情。我最终会选择多二进制解决方案。
作为参考,这里是 James Grennings 的回答:
You may want to mock A() when testing B().
for example
If I have a message_dispatcher() that reads a command from a serial port via getline(), and getline() uses getc() and getc() uses IORead and IOWrite. I could mock IORead and IOWrite and have a set of horrible tests to test the message_dispatcher().
Or I could test getc() with mock IORead() and IOWrite(), getline() with some kind of fake_getc(), and test message_dispatcher() with fake_getline(). If you only use linker substitution, you would need three tests builds. If you used function pointers you could do one test build. You can mix an match too.
getc() should be tested with link time mocks of IORead and IOWrite because your unit tests never want the real IORead and IOWrite for off-target tests (they may be needed of on-target tests, but those would be integration tests).
There are many possibilities. You could also have some other code getline() and feed it to the dispatcher, removing its dependencies.