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
Related
So I have a class which is calling method from other class, but eventually it will return a string or so
This is my class: Person.cpp
Person::Person(){}
std::string Person::getName(void) {
return namespaceX::namespaceY::StringVal;
}
This is my mock / test class:
class MockPerson : public Person{
public:
typedef ::testing::StrictMock<Person> Strict;
MockPerson() : Person(){}
~MockPerson() override = default;
MOCK_METHOD0(getName, std::string ());
std::string callFunc(){
return Person::getName();
}
This is my test header file:
class PersonTest : public testing::Test {
public:
PersonTest () :
mock(std::make_shared<MockPerson ::Strict>()){}
~PersonTest (void) override = default;
std::shared_ptr<MockPerson ::Strict> mock;
};
This is my test:
#include "testHeader.hpp"
TEST_F(PersonTest , case1)
{
EXPECT_CALL(*mock, getName());
ASSERT_EQ(someString, mock->callFunc());
}
The test setup looks good to me however when I ran the test, it gives me:
Actual function call count doesn't match EXPECT_CALL(*mock, getName())...
Expected: to be called once
Actual: never called - unsatisfied and active
And the values return in the ASSERT statement is just the default value of the string ("").
Is there a way to go through it? I saw online that we should pass in an actual object to the function but in this case a very simple function causes more troubles than complex ones. Any help is appreciated.
First, compiling your example with g++ gives me the following error:
error: 'using element_type = class testing::StrictMock<Person>' {aka 'class testing::StrictMock<Person>'} has no member named 'gmock_getName'
This can be fixed by passing MockPerson as the template parameter for StrictMock, instead of passing Person:
typedef ::testing::StrictMock<MockPerson> Strict;
Second, your declaration of callFunc explicitly calls the getName function of the Person class. This bypasses the mocked version of getName and hence the instrumentation that Google Mock inserts to keep track of the number of function calls. Therefore, you get the assertion failure about the function call count mismatch. This can be fixed by making callFunc call the getName of the current class (MockPerson) instead:
std::string callFunc() { return getName(); }
Third, the mocked getName will return a default-constructed std::string, hence you get the "". You can change the behavior for all tests belonging to PersonTest, by adding this declaration in the PersonTest constructor:
ON_CALL(*mock, getName()).WillByDefault(Return("xyz"));
Or you can set the behavior for individual tests by modifying the EXPECT_CALL declarations to:
EXPECT_CALL(*mock, getName()).WillRepeatedly(Return("xyz"));
For both variants, the assert for your callFunc should then work as expected:
ASSERT_EQ("xyz", mock->callFunc());
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.
I want to call ClassA.mockMethod() whenever objOfClassB.realMethod() method is invoked.
public class ClassA{
public static int mockMethod(String url, MySql sql){
int res=0
// do work
return ;
}
}
Definition of executeUpdate1()
class Veps{
protected synchronized int realMethod(String url, MySql sql){
----
-----
}
}
public class VepsTest {
public void setUp() throws Exception {
veps = mock(Veps.class);
when(objOfClassA.realMethod(any(String.class), any())).thenReturn(objOfClassB.mockMethod(any(String.class),any()));
}
}
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
2 matchers expected, 4 recorded.
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));
the mockito reports the errors clearly:
Invalid use of argument matchers! 2 matchers expected, 4 recorded.
you shouldn't using Matchers in any then* clause. your problem can be fixed as:
when(veps.executeQuery1(any(String.class), any(MySql.class)))
.thenReturn(DBConnection.mockExecuteQuery("??","??"));
when(veps.executeUpdate1(any(String.class), any()))
.thenReturn(DBConnection.mockExecuteUpdate("??","??"));
but another problem appears: why did you need query the result from the database? you can simply take a constant value to fake the result:
when(veps.executeQuery1(any(String.class), any(MySql.class)))
.thenReturn(1);
// ^--- replace the constant 1 with yours
when(veps.executeUpdate1(any(String.class), any()))
.thenReturn(1);
// ^--- replace the constant 1 with yours
you need to see mockito documentation as further before using it in your test.
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.
I have a method (method1) that I'd like to test, which based on parameters provided creates an object and calls another method (method2). So I'm mocking method2, which accepts an object (sampleObj).
public void method1(booleanParam) {
if(booleanParam){
List<SampleObj> fooList = new ArrayList<SampleObj>;
fooList.add(new SampleObj("another param"));
anotherService.method2(fooList);
}
//some other smart logic here
}
And here's my test with same obfuscated names (sorry if I missed any typo):
public void testMethod1() {
AnotherService mockedAnotherService = PowerMockito.mock(AnotherService.class);
ServicesFactory.getInstance().setMock(AnotherService.class, mockedAnotherService);
List<SampleObj> fooList = new ArrayList<SampleObj>;
fooList.add(new SampleObj("another param"));
// assert and verify
service.method1(true);
Mockito.verify(mockedAnotherService, times(1)).method2(fooList);
}
The problem is, when I try to mock the anotherService, I need to pass an object to method2, so I have to create a new one. But since it's a new object, it's not the same object, which will be passed from inside the method1, hence the test fails with the exception:
Argument(s) are different! Wanted:
anotherService.method2(
[com.smart.company.SampleObj#19c59e46]
);
-> at <test filename and line # here>
Actual invocation has different arguments:
anotherService.method2(
[com.smart.company.SampleObj#7d1a12e1]
);
-> at <service filename and line # here>
Any ideas how to accomplish that?
You have a few options:
Implement equals and hashCode on SampleObj. Because you didn't wrap fooList in a matcher, Mockito checks with List.equals, which checks equals for corresponding objects in each List. The default behavior of Object.equals is that a.equals(b) iff a == b--that is, objects are equal iff they refer to the same instance--but you're welcome to override that if every SampleObj("foobar") equals every other SampleObj("foobar").
Use a Hamcrest Matcher you write.
private static Matcher<List<SampleObj>> isAListWithObjs(String... strings) {
return new AbstractMatcher<List<SampleObj>>() {
#Override public boolean matches(Object object) {
// return true if object is a list of SampleObj corresponding to strings
}
};
}
// in your test
verify(mockedAnotherService).method2(argThat(isAnObjListWith("another param")));
Note that you could also just make a Matcher of a single SampleObj, and then use a Hamcrest wrapper like hasItem. See more matchers here.
Use a Captor to check equals your own way:
public class YourTest {
// Populated with MockitoAnnotations.initMocks(this).
// You can also use ArgumentCaptor.forClass(...), but with generics trouble.
#Captor ArgumentCaptor<List<SampleObj>> sampleObjListCaptor;
#Test public void testMethod1() {
// ...
verify(mockedAnotherService).method2(sampleObjListCaptor.capture());
List<SampleObj> sampleObjList = sampleObjListCaptor.getValue();
assertEquals(1, sampleObjList.size());
assertEquals("another param", sampleObjList.get(0).getTitle());
}