'GoogleTest EXPECT_CALL throws uninteresting call warning and returns 0 calls
I am trying to Mock an external library and test what APIs of the library are being called from my interfaces and I have come across a behavior (first time using mocking) that I can't seem to understand. So, I have a mock class like this:
class VulkanLibMock {
public:
MOCK_METHOD(VkResult, vkCreateDescriptorSetLayout, (VkDevice, const VkDescriptorSetLayoutCreateInfo *, const VkAllocationCallbacks *, VkDescriptorSetLayout *pSetLayout));
MOCK_METHOD(VkResult, vkCreateDescriptorPool, (VkDevice, const VkDescriptorPoolCreateInfo *, const VkAllocationCallbacks *, VkDescriptorPool *));
};
and a test base class to handle values:
class VulkanBaseTest : public ::testing::Test {
public:
VulkanBaseTest() {
vulkanLibMock = new ::testing::NiceMock<VulkanLibMock>;
}
~VulkanBaseTest() {
delete vulkanLibMock;
vulkanLibMock = nullptr;
}
public:
static VulkanLibMock *vulkanLibMock;
};
So, I inherited a test class from it:
class VulkanDescriptorManagerTests : public VulkanBaseTest {
public:
VulkanDescriptorManagerTests() = default;
};
and added one test case:
TEST_F(VulkanDescriptorManagerTests, MyTest) {
ON_CALL(*vulkanLibMock, vkCreateDescriptorSetLayout).WillByDefault([](VkDevice, const VkDescriptorSetLayoutCreateInfo *, const VkAllocationCallbacks *, VkDescriptorSetLayout *) {
std::cout << "Called: vkCreateDescriptorSetLayout";
return VK_SUCCESS;
});
ON_CALL(*vulkanLibMock, vkCreateDescriptorPool).WillByDefault([](VkDevice, const VkDescriptorPoolCreateInfo *, const VkAllocationCallbacks *, VkDescriptorPool *) {
std::cout << "Called: vkCreateDescriptorPool";
return VK_SUCCESS;
});
// this is the class that I am trying to test
VulkanDescriptorManager manager(nullptr);
EXPECT_CALL(*vulkanLibMock, vkCreateDescriptorSetLayout);
}
If I don't use NiceMock
, I get the following warning when running tests
Called: vkCreateDescriptorSetLayout <-- cout in `ON_CALL`
Uninteresting mock function call - taking default action specified at:
VulkanDescriptorManager.test.cpp:12:
Function call: vkCreateDescriptorSetLayout(NULL, 0x7ffeefbfec50, NULL, 0x7ffeefbfedf0)
Returns: 0
NOTE: You can safely ignore the above warning unless this call should not happen. Do not suppress it by blindly adding an EXPECT_CALL() if you don't mean to enforce the call. See https://github.com/google/googletest/blob/master/docs/gmock_cook_book.md#knowing-when-to-expect for details.
Called: vkCreateDescriptorSetLayout <-- cout in `ON_CALL`
GMOCK WARNING:
Uninteresting mock function call - taking default action specified at:
VulkanDescriptorManager.test.cpp:12:
Function call: vkCreateDescriptorSetLayout(NULL, 0x7ffeefbfec20, NULL, 0x7ffeefbfedf8)
Returns: 0
NOTE: You can safely ignore the above warning unless this call should not happen. Do not suppress it by blindly adding an EXPECT_CALL() if you don't mean to enforce the call. See https://github.com/google/googletest/blob/master/docs/gmock_cook_book.md#knowing-when-to-expect for details.
Called: vkCreateDescriptorPool <-- cout in `ON_CALL`
GMOCK WARNING:
Uninteresting mock function call - taking default action specified at:
VulkanDescriptorManager.test.cpp:17:
Function call: vkCreateDescriptorPool(NULL, 0x7ffeefbfeca0, NULL, 0x7ffeefbfee00)
Returns: 0
NOTE: You can safely ignore the above warning unless this call should not happen. Do not suppress it by blindly adding an EXPECT_CALL() if you don't mean to enforce the call. See https://github.com/google/googletest/blob/master/docs/gmock_cook_book.md#knowing-when-to-expect for details.
And, I get an error regardless of using NiceMock:
Actual function call count doesn't match EXPECT_CALL(*vulkanLibMock, vkCreateDescriptorSetLayout)...
Expected: to be called once
Actual: never called - unsatisfied and active
What am I missing here? I know that the function is called since can see the output of cout
statement in ON_CALL
implementation. Why does EXPECT_CALL
thinks that the function is not called?
EDIT: VulkanDescriptorManager (simplified):
VulkanDescriptorManager(VkDevice device) {
// global library functions
VkDescriptorSetLayoutCreateInfo sceneCreateInfo{};
vkCreateDescriptorSetLayout(device, &createInfo, nullptr, &this->sceneDescriptorSet);
VkDescriptorSetLayoutCreateInfo materailCreateInfo{};
vkCreateDescriptorSetLayout(device, &materailCreateInfo, nullptr, &this->materialDescriptorSet);
// same logic for vkCreateDescriptorPool
}
The called functions are global and were coming from library. In order to be able to test them, I unlinked the library and created my own implementation for the functions:
// this is in my global library mock file:
VkResult vkCreateDescriptorSetLayout(
VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkDescriptorSetLayout *pSetLayout) {
// Calls the function in mock that is accessible from
// VulkanBaseTest's static variable
return VulkanBaseTest::vulkanLibMock->vkCreateDescriptorSetLayout(device, pCreateInfo, pAllocator, pSetLayout);
}
VkResult vkCreateDescriptorPool(VkDevice device,
const VkDescriptorPoolCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkDescriptorPool *pDescriptorPool) {
return VulkanTestFixture::vulkanLibMock->vkCreateDescriptorPool(device, pCreateInfo, pAllocator, pDescriptorPool);
}
Solution 1:[1]
According to the gmock doc
Important note: gMock requires expectations to be set before the mock functions are called, otherwise the behavior is undefined. Do not alternate between calls to EXPECT_CALL() and calls to the mock functions, and do not set any expectations on a mock after passing the mock to an API.
Your code need to adjust these two lines sequence from:
VulkanDescriptorManager manager(nullptr);
EXPECT_CALL(*vulkanLibMock, vkCreateDescriptorSetLayout);
to:
EXPECT_CALL(*vulkanLibMock, vkCreateDescriptorSetLayout);
VulkanDescriptorManager manager(nullptr);
The doc has also explained why they use such design:
Why does gMock work like that? Well, specifying the expectation beforehand allows gMock to report a violation as soon as it rises, when the context (stack trace, etc) is still available. This makes debugging much easier.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |