GoogleMock SetArgReferee behavior for polymorphic arguments - c++

I'm attempting to mock a DB interface call and return a polymorphic data type as a reference using SetArgReferee. The method I'm mocking takes 2 base class reference arguments. While setting the value for the 2nd reference argument in SetArgReferee, a derived class object is used as the value. In the source code under test, the returned 2nd reference argument is again cast to the derived class and used. This seems to be not working properly.
I have a DBInterface that I'm mocking as below.
class DBInterface {
...
public:
virtual void service(Msg& req, Msg& resp, bool flag) = 0;
...
};
class DBInterfaceMock : public DBInterface {
public:
MOCK_METHOD3(service, void(Msg& req, Msg& resp, bool flag));
};
The test mocks this service call using the EXPECT_CALL as shown below
TEST_F(SessionTest, SessionInt) {
DBInterfaceMock mockDb;
Session* session = new Session(mockDb);
// DerivedMsg inherits from Msg and contains a map
DerivedMsg derivedMsg;
// populating the map inside the derivedMsg
// ...
// ...
EXPECT_CALL(mockDb, service(_, _, false))
.Times(1)
.WillDo(SetArgReferee<1>(*(dynamic_cast<Msg*>(&derivedMsg))));
session->init();
....
....
}
On calling the session->init(), I'm expecting that the mocked service call must return the values as populated in derivedMsg. However, the code hits an ASSERT where the map size is 0 even though the value to be returned in the SetArgReferee has been populated correctly.
In the production code, once the service call executes successfully, the reference argument is retrieved by doing a dynamic_cast to the desired derived type as shown below.
service(req, resp, false);
DerivedMsg derivedResp = *(dynamic_cast<DerivedMsg*>(&resp));
uint16_t size = derivedResp.getMap().size(); //returns a 0 size.
Is there a better way of achieving this? It doesn't seem to be working this way.

Related

Verify content of nlohmann json which is member of mocked method argument

Assume I got a some Message class object which has nlohmann json as private member and public getter:
class Message{
public:
nlohmann::json getJson() { return json_;}
...
private:
nlohmann::json json_;
...
};
Also there is a class that publishes the message
ex:
class Foo {
public:
publish(const Message& message)
...
};
In the test I am mocking the Foo::publish method and in some scenario I want to check if json_["key1"]["key2"] value is different than "" (empty string)
EXPECT_CALL(
*foo_mock_pointer,
publish(x) // x is the unknown code
);
For checking the value of the json object I guess it will be enough:
testing::Contains(testing::Pair("key1", testing::Pair("key2"), testing::Ne("")))
But I cant figure out how to get the json from Message object which is the argument of the mocked method.
IIUC, it looks like you want to check something about the argument that is passed to your mock function.
You can use SaveArg to save that argument inside a variable and then check its value later:
Message message;
EXPECT_CALL(
*foo_mock_pointer,
publish(x) // x is the unknown code
).WillOnce(DoAll(SaveArg<0>(&message), Return(/*Whatever you want to return*/)));
// Call your class-under-test API here
// ...
// Now check the message:
EXPECT_THAT(message.getJson(), /*Insert your matcher here*/);
See here for more info: http://google.github.io/googletest/gmock_cook_book.html#SaveArgVerify

Using spy to mock a full object created in the class which is tested

I have the following structure:
class A {
public A(String p){
// ...
}
public String AMethod(String p){
// ...
}
}
class B {
int method(String param){
A a = new A(param); int n;
String s = A.AMethod(param);
// ... (initializes n, ...)
return n;
}
}
Now I want to test method in class B but control the output of AMethod when it is called. But since I do not create the object A in the test class of B, I cannot mock it normally - how can I mock object A instead?
I tried Mockito.spy but it doesn't seem to work:
this.ASpy = spy(new A());
when(ASpy.createSession(any())).then(invocation -> {
// ... (*)
});
(*) still doen't get called... but spy should be the right solution, shouldn't it? My problem is: I never create an object A in my test class, only in method such an object is created but not in the test class.
The best way to handle this (if possible) would be to modify the code of class B so that object A was injected into the method (passed as a parameter, set as a class field or instantiated with usage of a factory class - the factory would be injected as a field and the factory object could be mocked in the test to return a mocked object A).
If actual code modifications are not possible, you could use PowerMock's whenNew method and return a mocked object in your test.
A side note: if you're using JUnit 5, PowerMock may not be a viable solution - read more here.

How to override the default ON_CALL action for just one EXPECT_CALL and go back to the default action later

I would like to test the method of my system, whose return value partially depends on the return value of the call to some kind of connection interface. In most cases I would like the IConnection to return true upon any kind of call to it's open(_, _) method. Except in one case, when I explicitly test for the condition with failed connection.
Example:
/*
* Some kind of network interface with method `open`
*/
class IConnection {
public:
IConnection() = default;
virtual ~IConnection() = default;
virtual bool open(const std::string& address, int port) = 0;
};
class ConnectionMock: public IConnection {
public:
MOCK_METHOD2(open, bool(const std::string& address, int port));
};
class MySystem {
public:
MySystem() = delete;
MySystem(std::shared_ptr<IConnection> connection): connection_(connection) {}
bool doSth() {
/*
* Do some things, but fail if connection fails
*/
bool connectionStatus = connection_->open("127.0.0.1", 6969);
if (!connectionStatus) {
return false;
}
// do other things
return true;
}
private:
std::shared_ptr<IConnection> connection_;
};
TEST(MySystemShould, returnFalseIfFailedToOpenConnectionAndTrueIfSucceeded) {
auto connectionMock = std::make_shared<NiceMock<ConnectionMock> >();
ON_CALL(*connectionMock, open(_, _)).WillByDefault(Return(true));
MySystem system(connectionMock);
// if I don't specify Times test fill fail, because WillOnce automatically sets Times(1)
EXPECT_CALL(*connectionMock, open(_, _)).Times(AnyNumber()).WillOnce(Return(false));
/*
* Commented code below is not a good solution - after expectation retires
* the test will fail upon subsequent calls
*/
//EXPECT_CALL(*connectionMock, open(_, _)).WillOnce(Return(false)).RetiresOnSaturation();
ASSERT_FALSE(system.doSth());
/*
* Code bellow allows me to avoid the warning
*/
//EXPECT_CALL(*connectionMock, open(_, _)).WillRepeatedly(Return(true));
ASSERT_TRUE(system.doSth());
}
The problems with my current solution is that when the EXPECT_CALL override becomes saturated, even though gmock goes back to the default action specified on ON_CALL, every subsequent call to open(_, _) is causing the following warning:
GMOCK WARNING:
/whatever.cpp:105: Actions ran out in EXPECT_CALL(*connectionMock, open(_, _))...
Called 2 times, but only 1 WillOnce() is specified - taking default action specified at:
/whatever.cpp:103:
even though I'm using NiceMock. I can get rid of the warning by specifying EXPECT_CALL with WillRepeatedly(Return(true)), but this is the duplication of my code in ON_CALL.
I would like to know, how can I override the default action specified with ON_CALL for just one call to IConnection::open, and then go back to the defaults, without causing gmock to print a warning. The perfect solution would be something similar to:
EXPECT_CALL(*connectionMock, open(_, _)).WillOnce(Return(false)).DisableExpectationAfterSaturation();
but it doesn't exist. RetiresOnSaturation doesn't work as I would like, because it fails the test after getting saturated (doesn't match action specified with ON_CALL).
EDIT 2
The DoDefault() - feature comes close to what is asked in the question. It specifies that an action in EXPECT_CALL should go back to the default action specified by ON_CALL:
using ::testing::DoDefault;
// Default action
ON_CALL(*connectionMock, open(_, _)).WillByDefault(Return(true));
// returns true once and then goes back to the default action
EXPECT_CALL(*connectionMock, open(_, _)
.WillOnce(Return(false))
.WillRepeatedly(DoDefault());
Initial answer
If the return value of IConnection::open depends on the parameters you can specify ON_CALL twice but with different arguments (or rather arguments instead of the placeholder):
ON_CALL(*connectionMock, open(_, _)).WillByDefault(Return(true));
ON_CALL(*connectionMock, open("BAD_ADDRESS", 20)).WillByDefault(Return(false));
So any time the mocked method open will be called with arguments "BAD_ADDRESS" and 20, it will return false, and true otherwise.
Here is a simple example:
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::Return;
class A {
public:
virtual bool bla(int a) = 0;
};
class MOCKA : public A {
public:
MOCK_METHOD1(bla, bool(int));
};
TEST(ABC, aBABA) {
MOCKA a;
ON_CALL(a, bla(_)).WillByDefault(Return(false));
ON_CALL(a, bla(1)).WillByDefault(Return(true));
EXPECT_CALL(a, bla(_)).Times(AnyNumber());
EXPECT_TRUE(a.bla(1));
EXPECT_TRUE(a.bla(1));
EXPECT_TRUE(a.bla(1));
EXPECT_FALSE(a.bla(2));
EXPECT_FALSE(a.bla(3));
EXPECT_FALSE(a.bla(4));
}
EDIT 1
I think now I understood the problem and if I did then the solution is very simple:
EXPECT_CALL(*connectionMock, open(_, _))
.Times(AnyNumber())
.WillOnce(Return(true))
.WillRepeatedly(Return(false));
When ConnectionMock::open will be called inside of MySystem::doSth it will once return true and then always return false no matter what the arguments are. In this case you also don't need to specify ON_CALL. Or do you definitely need to specify the actions with ON_CALL instead of EXPECT_CALL?

GMOCK how to assign values to function arguments

I have a function like below:
FnCall(request, response);
where request and reply type are of a class - Message. Now I have mocked the method like below:
class MessageMock : public Message
{
public:
MOCK_METHOD2(FnCall, bool(const Message* request, Message*& response));
};
In my test case I have an expect call to FnCall
EXPECT_CALL(mMessageMock, FnCall(::testing::_,::testing::_));
My requirement is to set some dummy value in the request / response argument in function FnCall of type MessageMock - how can I set that?
=======================================================================
I tried the below code:
MessageMock MessageMock1, MessageMock2;
EXPECT_CALL(mMessageMock, FnCall(&mMessageMock1,
&mMessageMock2));
But receive compilation error and even tried with const declaration:
error: no matching function for call to 'gmock_FnCall(MessageMock*, MessageMock*)'
note: candidate is:
note: testing::internal::MockSpec<bool(const Message*, Message*&)>&
note: no known conversion for argument 2 from 'MessageMock*' to 'const testing::Matcher<Message*&>&'
You are doing this wrong. Your expectation is just on mMessageMock so just that object should be mock. (You are expecting on mock instance) if the test is the caller:
mMessageMock.method(...)
you need to provide dummy objects for that call.
Lets say you have interface like this:
class MyInterface{
public:
virtual void method(MyInterface*, MyInterface*) = 0;
};
and you want to check is some method called on that interface. You define mock class and set expectation on that instance of that mock.
class MyMock : public MyInterface{
public:
MOCK_METHOD2(method, void(MyInterface*,MyInterface*);
};
For your test you need to provide Dummy object to complete interface:
class MyDummy : public MyInterface{
public:
void method(MyInterface*, MyInterface*) override{}
};
So, in your test add:
MyMock mock;
MyDummy request, response;
EXPECT_CALL(mock, method(&request, &response));
and if you want to test this without rest of the code. Just call that method on mock instance after you set expectation.
mock.method(&request,&response);
Here I provide dummy values.
EDIT:
Updated to improve usage of dummy objects.

How to use thenAnswer with method which returns void

I want to unit test following method
public void addRecord(Record record)
{
Myclass newObj = new Mycalss();
// It creates newObj object, set some values using record object.
// and it adds the newObj in daatbase.
dataReqDao.persist(newObj);
}
I have mocked dataReqDao.persist method but how can I verify if right values are copied into newObj object? I want to get the newObj object.
I think thenAnswer will be the appropraite method to retrieve newObj ie method arguments but dont know how to use it method which returns void.
Update:
I tried
doAnswer(new Answer<Myclass>() {
public Myclass answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
return (Myclass)args[0];
}
}).when(dataReqDao.persist(any(Myclass.class)));
EDIT:
It should be (Thanks David)
doAnswer(new Answer<Myclass>() {
public Myclass answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
return (Myclass)args[0];
}
}).when(dataReqDao).persist(any(Myclass.class));
You can create a custom argument matcher that would check fields of that object, or use an argument captor to capture the object for further inspection.
For example, as follows:
ArgumentCaptor<Myclass> c = ArgumentCaptor.forClass(Myclass.class);
verify(dateReqDao).persist(c.capture());
Myclass newObj = c.getValue();
... // Validate newObj
You need to make it with thenAnswer (or then which i personally prefer), so you can assert/verify the values at the time of method call, in the method.
when(dataReqDao.persist(newObj)).then(new Answer<Void>() {
#Override
public Void answer(final InvocationOnMock invocation) {
Myclass newObjActual = (Myclass) invocation.getArguments()[0];
// Control
assertEquals(..., newObjActual.getX());
assertEquals(..., newObjActual.getY());
return null;
}
});
// Run Test
x.addRecord(record);
Here is a detail explanation: https://akcasoy.wordpress.com/2015/04/09/the-power-of-thenanswer/ (Use case 2)
ArgumentCaptor does not test in a clever way. When you change your method like this:
public void addRecord(Record record)
{
Myclass newObj = new Mycalss();
dataReqDao.persist(newObj);
// first persist, than set attributes
newObj.setX(..);
}
.. your test with Captor still runs, but it should fail. Since the ArgumentCaptor does not capture that state of the object at the time of call, but just the objectId, it does not matter for captor whether you set your attributes before or after dao call. Yet a good test should fail with every functional change. Here is my article exactly about this case:
https://akcasoy.wordpress.com/2015/02/03/how-to-ensure-quality-of-junit-tests/ (the above stubbing with the then is a better approach though than the one with InOrder approach)
Myclass newObj = new Myclass();
That line troubles me. If you are using dependency injection, you should have your factory send you an instance of that object. Then, when you create your unit tests, you can have the test factory send in a mock instance of MyClass which the unit test can also have access to. Then you can use axtavt's captor to see if it really did what it was supposed to do. There's nothing wrong with the unit test the way you did it, it's just that any() is kind of weak given that you know it is passing in an object of that type--what you want to know in the test is whether the object is the one you intended and has not been modified.