PowerMock + EasyMock unexpected method call - unit-testing

I have a method like this which I want to unit test
public void update(String collectionName, BasicDBObject query, BasicDBObject updateObj){
try{
DBCollection collection = getCollection(collectionName);
collection.update(query, updateObj, true, false);
} catch (MongoException e) {
if (e.getMessage().startsWith("can't call something")) {
refreshConnection(collectionName);
} else {
throw e;
}
}
}
And the test code is as below. I have tried both the methods in the comments in unit test case and currently have commented it.
#Test
public void testUpdate(){
MongoStore store = PowerMock.createStrictPartialMockForAllMethodsExcept(MongoStore.class, "update");
DBCollection collection = PowerMock.createMock(DBCollection.class);
BasicDBObject updateobj = new BasicDBObject("test","shrikar");
String name = "testcoll";
String id = "123";
BasicDBObject query = new BasicDBObject("id",id);
EasyMock.expect(store.getCollection(name)).andReturn(collection);
//EasyMock.expect(collection.update(EasyMock.anyObject(BasicDBObject.class),EasyMock.anyObject(BasicDBObject.class),EasyMock.anyBoolean(),EasyMock.anyBoolean()));
//EasyMock.expect(collection.update(query,updateobj,true,false));
PowerMock.replayAll();
store.update(name,query,updateobj);
EasyMock.expectLastCall().times(1);
PowerMock.verifyAll();
}
In all the cases I keep getting
Unexpected Method call DBCollection.update({"id":"123"},{"test":"shrikar"}, true, false)
What am I missing?

Ok I found out the problem I had forgotten to add Mongo*.class to PrepareForTest
#PrepareForTest({MongoStore.class,MongoOptions.class,Mongo.class, BasicDBObject.class,DBCursor.class,DBObject.class})

Related

How can I prevent a method call when JUnit testing with Mockito?

For the life of me, I can't seem to figure out how to prevent the method I'm testing from calling a method in another class.
Here is my test class:
#ExtendWith(MockitoExtension.class)
class QueryHandlerTest {
#InjectMocks
QueryHandler queryHandler;
#Mock
ResponseBuilder responseBuilder;
#BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}
#Test
void TC5() {
doThrow(AddMessageResponseException.class).when(responseBuilder).addMessageResponse(isA(Boolean.class), isA(Boolean.class));
assertThrows(AddMessageResponseException.class, ()-> queryHandler.addMessage("Hello",true));
}
}
Here is the method that I'm testing:
public void addMessage(String message, boolean lengthExceedsLimit) {
boolean messageAdded;
if (checkIfJarExists()) {
if (!lengthExceedsLimit) {
// attempt to add the message to the jar
messageAdded = addMessageQuery(new Message(event.getMessageAuthor().getIdAsString(), message));
} else {
messageAdded = false;
}
} else {
messageAdded = false;
}
responseBuilder.addMessageResponse(messageAdded, lengthExceedsLimit);
if (messageAdded) {
// check to see if the jar's message limit has been reached; if so, perform opening ceremony
if (checkMessageLimit()) {
responseBuilder.performOpeningEvent(currentJar);
deleteJarQuery(this.serverId);
}
}
}
And here is the method that it's calling:
public void addMessageResponse(boolean messageAdded, boolean lengthExceedsLimit){
if (lengthExceedsLimit) {
event.getChannel().sendMessage("I'm sorry, your message is too long. Please limit your message " +
"to 250 characters or less.");
} else if(messageAdded){
String nickname = getNickname();
event.getChannel().sendMessage("Thanks, " + nickname + "! Your message has " +
"been added to the jar!");
} else {
event.getChannel().sendMessage("Sorry, it looks like a jar has not been set up for your server. " +
"If you're a server admin, you can create a jar! " +
"Please use '!tiko help' to see a list of my commands.");
}
}
When I run the test, I get this output:
org.opentest4j.AssertionFailedError: Unexpected exception type thrown,
Expected :class com.tikoJar.exceptions.AddMessageResponseException
Actual :class java.lang.NullPointerException
<Click to see difference>
...
Caused by: java.lang.NullPointerException: Cannot invoke "org.javacord.api.entity.channel.TextChannel.sendMessage(String)" because the return value of "org.javacord.api.event.message.MessageCreateEvent.getChannel()" is null
at com.tikoJar.DTO.ResponseBuilder.addMessageResponse(ResponseBuilder.java:35)
at com.tikoJar.DTO.QueryHandler.addMessage(QueryHandler.java:74)
at com.tikoJar.DTO.QueryHandlerTest.lambda$TC5$0(QueryHandlerTest.java:68)
at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:53)
... 73 more
As you can see, the method I'm testing is calling and running the addMessageResponse() method in the ResponseBuilder class, even though I specified in my test that a custom exception should be thrown when attempting to call that method.
I've also tried specifying:
doNothing().when(responseBuilder).addMessageResponse(isA(Boolean.class), isA(Boolean.class));
... but the method still gets called and run. What can I do here?

how to test method with resultSet and preparedStatement

i would like to unit test my method, which return from database id of last inserted object:
public int getLastId() throws SQLException {
String query = "select LAST_INSERT_ID();";
PreparedStatement stmt = connection.prepareStatement(query);
int id = -1;
ResultSet resultSet = stmt.executeQuery();
while (resultSet.next()) {
id = resultSet.getInt("LAST_INSERT_ID()");
}
return id;
}
and then i want to do same unit test like this:
dataBaseService = mock(DataBaseService.class);
resultSet = mock(ResultSet.class);
#Test
public void getLastIdIsCorrect() throws SQLException {
//given
int expectedId = 1;
int expectedIncorrectId = 101;
//when
when(resultSet.getInt("LAST_INSERT_ID()")).thenReturn(1);
when(dataBaseService.getLastId()).thenCallRealMethod();
int result = dataBaseService.getLastId();
//then
Assert.assertEquals(expectedId, result);
Assert.assertNotEquals(expectedIncorrectId, result);
}
But i'm getting Null pointer exception at line with PreparedStatement stmt = connection.prepareStatement(query);
Can you explain me please, how to do unit tests like this correctly? I have few methods left with the same problem and i'm still learning unit tests....
The problem is, that you seem to be unclear what you are testing. If you are testing the code of getLastId then you should not mock the class containing it - DataBaseService - normally. Instead, your test would be a test OF DataBaseService with something like this...
Connection connection = mock(Connection.class);
PreparedStatement stmt = mock(PreparedStatement.class);
...and...
when(connection.prepareStatement(Mockito.anyString())).thenReturn(stmt);
when(stmt.executeQuery()).thenReturn(resultSet);
When you are outside of DataBaseService and want to test something that's calling it, then you can mock DataBaseService and simply return a number then. But for testing DataBaseService it's not needed to do something like...
dataBaseService = mock(DataBaseService.class);
...
when(dataBaseService.getLastId()).thenCallRealMethod();
Simply create a new instance of DataBaseService and mock the things "inside" it, for example the Connection.
To show some more code, it would be required to know the setup of your class and also which JUnit version you are using.
Ok, thx for your answer :)
i've changed and created DataBaseService object, and then tried to mock everything inside like this:
#Test
public void getLastIdIsCorrect() throws SQLException {
//given
int expectedId = 1;
int expectedIncorrectId = 101;
//when
when(DriverManager.getConnection(Mockito.anyString(), Mockito.anyString(), Mockito.anyString())).thenReturn(connection);
when(connection.prepareStatement(Mockito.anyString())).thenReturn(stmt);
when(stmt.executeQuery()).thenReturn(resultSet);
int result = dataBaseService.getLastId();
//then
Assert.assertEquals(expectedId, result);
Assert.assertNotEquals(expectedIncorrectId, result);
}
and now i'm getting that exception and headache too :D :
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure

how to apply in DebuggerHiddenAttribute dependent/cascade methods

I'm trying to ignore a exception that happen when run my test Methods.
I`m using a unitTest proyect.
The problem apears when
TestCleanup Method runs. It's a recursive method. This method clean all entities created in DB during the test. This is a recursive method because of dependences.
Anyway this method call to delete generic method in my ORM(Petapoco). It throws an exception if it can't delete the entity. Any problem, it run again with recursive way until delete it.
Now the problem, if i'm debugging VS stop a lot of times in Execute method because of failed deletes. But I can't modify this method to ignore it. I need a way to ignore this stops when i'm debugging tests. A way like DebuggerHiddenAttribute or similar.
Thanks!
I tried to use DebuggerHiddenAttribute, but cannot works in methods called by main method.
[TestCleanup(), DebuggerHidden]
public void CleanData()
{
ErrorDlt = new Dictionary<Guid, object>();
foreach (var entity in TestEntity.CreatedEnt)
{
try
{
CallingTest(entity);
}
catch (Exception e)
{
if (!ErrorDlt.ContainsKey(entity.Key))
ErrorDlt.Add(entity.Key, entity.Value);
}
}
if (ErrorDlt.Count > 0)
{
TestEntity.CreatedEnt = new Dictionary<Guid, object>();
ErrorDlt.ForEach(x => TestEntity.CreatedEnt.Add(x.Key, x.Value));
CleanData();
}
}
public int Execute(string sql, params object[] args)
{
try
{
OpenSharedConnection();
try
{
using (var cmd = CreateCommand(_sharedConnection, sql, args))
{
var retv = cmd.ExecuteNonQuery();
OnExecutedCommand(cmd);
return retv;
}
}
finally
{
CloseSharedConnection();
}
}
catch (Exception x)
{
OnException(x);
throw new DatabaseException(x.Message, LastSQL, LastArgs);
}
}
Error messages are not required.

Junit error - No value present or no such element

testclass.java
#Test
public void testgetDictionaryValueListById() {
DictionaryValue dictionaryValue = new DictionaryValue();
dictionaryValue.setId(1);
dictionaryValue.setValueName("Test Dictionary Value");
dictionaryValue.setValueKey("12345678");
dictionaryValue.setStatus("Active");
dictionaryValue.setCreatedOn(new Date());
dictionaryValue.setUpdatedOn(new Date());
Mockito.when(dictionaryValueRepo.findById(1).get()).thenReturn(dictionaryValue);
assertThat(dictionaryService.getDictionaryValueListById(1)).isEqualTo(dictionaryValue);
}
Service.java
public DictionaryValue getDictionaryValueListById(int id) {
return dictionaryValueRepo.findById(id).get();
}
Repo.java
#Repository
public interface DictionaryValueRepo extends JpaRepository<DictionaryValue, Integer> {
}
I am getting no such value present again and again on executing test case in testclass.java. I don't know why? but when I am running my service method from the controller it is working as expected - fetching records from the database but not working in a test case.
Your test should be like this and please check out the naming. You need to Mock the step findId() befor the `get().
#InjectMocks
Service cut;
#Mock
DictionaryValueRepo dictionaryValueRepoMock;
// Can skipped by adding a #RunWith... on Testclass
#Before
public init() {
Mockito.initMocks(this);
}
#Test
public void testgetDictionaryValueListById() {
// Prepare Data
final int testId = 1;
DictionaryValue dictionaryValue = new DictionaryValue();
dictionaryValue.setId(testId);
dictionaryValue.setValueName("Test Dictionary Value");
dictionaryValue.setValueKey("12345678");
dictionaryValue.setStatus("Active");
dictionaryValue.setCreatedOn(new Date());
dictionaryValue.setUpdatedOn(new Date());
// config mocking
Mockito.when(dictionaryValueRepo.findById(testId)).thenReturn(<VALUE>);
Mockito.when(dictionaryValueRepo.findById(testId).get()).thenReturn(dictionaryValue);
// Call yout method for Testing
cut.getDictionaryValueListById(testId);
// verifies (if wanted) + assertions....
}
I concur with LenglBoy, so the right answer should be given to him.
The thing you need to be careful is what "VALUE" means in this line:
Mockito.when(dictionaryValueRepo.findById(testId)).thenReturn(VALUE);
The findById returns an Optional, so that is what you should build and pass to Mockito. Something like this:
Mockito.when(dictionaryValueRepo.findById(testId))
.thenReturn(Optional.ofNullable(dictionaryValue));
And for a scenario where the id does not exists in BD, passing Optional.empty() should be good enough.

Using Moq to mock a repository that returns a value

How do I set up my test method on that mocks a repository which accepts an object?
This is what I have so far:
Service.cs
public int AddCountry(string countryName)
{
Country country = new Country();
country.CountryName = countryName;
return geographicsRepository.SaveCountry(country).CountryId;
}
test.cs
[Test]
public void Insert_Country()
{
//Setup
var geographicsRepository = new Mock<IGeographicRepository>();
geographicsRepository.Setup(x => x.SaveCountry(It.Is<Country>(c => c.CountryName == "Jamaica"))); //How do I return a 1 here?
GeographicService geoService = new GeographicService(geographicsRepository.Object);
int id = geoService.AddCountry("Jamaica");
Assert.AreEqual(1, id);
}
SaveCountry(Country country); returns an int.
I need to do 2 things:
First test, I need to tell the setup to return an int of 1.
I need to create a second test Insert_Duplicate_Country_Throws_Exception(). In my Setup, how do I tell the repository to throw an error when I do:
int id = geoService.AddCountry("Jamaica");
int id = geoService.AddCountry("Jamaica");
Framework:
NUnit.
Moq.
ASP.NET MVC - repository pattern.
Your first test should look something like this:
[Test]
public void Insert_Country()
{
Mock<IGeographicRepository> geographicsRepository = new Mock<IGeographicRepository>();
GeographicService geoService = new GeographicService(geographicsRepository.Object);
// Setup Mock
geographicsRepository
.Setup(x => x.SaveCountry(It.IsAny<Country>()))
.Returns(1);
var id = geoService.AddCountry("Jamaica");
Assert.IsInstanceOf<Int32>(id);
Assert.AreEqual(1, id);
geographicsRepository.VerifyAll();
}
The second test should look like this:
[Test]
public void Insert_Duplicate_Country_Throws_Exception()
{
Mock<IGeographicRepository> geographicsRepository = new Mock<IGeographicRepository>();
GeographicService geoService = new GeographicService(geographicsRepository.Object);
// Setup Mock
geographicsRepository
.Setup(x => x.SaveCountry(It.IsAny<Country>()))
.Throws(new MyException());
try
{
var id = geoService.AddCountry("Jamaica");
Assert.Fail("Exception not thrown");
}
catch (MyException)
{
geographicsRepository.VerifyAll();
}
}
I think maybe you are slightly misunderstanding the purpose of testing with mocks in the two scenarios you have supplied.
In the first scenario, you wish to test that 1 is returned when you pass in "Jamaica". This is not a mock test case but a test case for real behaviour as you wish to test a specific input against an expected output i.e. "Jamaica" -> 1. In this situation mocking is more useful to ensure that internally your service calls SaveCountry on the repository with the expected country, and that it returns the value from the call.
Setting up your "SaveCountry" case and then calling "VerifyAll" on your mock is the key. This will assert that "SaveCountry" was indeed called with country "Jamaica", and that the expected value is returned. In this way you have confidence that your service is wired up to your repository as expected.
[Test]
public void adding_country_saves_country()
{
const int ExpectedCountryId = 666;
var mockRepository = new Mock<IGeographicRepository>();
mockRepository.
Setup(x => x.SaveCountry(It.Is<Country>(c => c.CountryName == "Jamaica"))).
Returns(ExpectedCountryId);
GeographicService service= new GeographicService(mockRepository.Object);
int id = service.AddCountry(new Country("Jamaica"));
mockRepo.VerifyAll();
Assert.AreEqual(ExpectedCountryId, id, "Expected country id.");
}
In the second scenario you wish to test that an exception is raised when you attempt to add a duplicate country. There's not much point in doing this with a mock as all you will test is that your mock has behaviour when adding duplicates, not your real implementation.