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
Related
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.
I have the following Java 8 DAO method that uses Spring JdbcTemplate to hit a database:
class MyAppDao {
#Inject
DataSource dataSource
public List<String> getFizzByBuzzIds(List<Integer> buzzIds) {
String sql = "SELECT * from buzzes WHERE buzz_id IN ( :buzzIds )";
NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
Map<String, Object> paramValues = new HashMap<>(1);
paramValues.put("buzzIds", buzzIds);
List<Buzz> buzzes = jdbcTemplate.query(sql,
paramValues, (rs, rowNum) -> {
return new Buzz(rs.getString("buzz_id"), rs.getString("buzz_key"),
rs.getString("buzz_external_id"));
}
);
List<String> fizzes = figureOutSomehow();
return fizzes;
}
}
I cannot change the dependencies injected into this method. The NamedParameterJdbcTemplate instance must be defined inside this method. The only thing I can mock (easily) is the dataSource.
I am trying (and I know, the method isn't written to be conducive to unit tests at all!) to write a Spock unit test for this, and just want to verify that when getFizzByBuzzIds is called, that jdbcTemplate.query is called (with any arguments).
My best attempt:
def 'getFizzByBuzzIds attempts to get case info from the DB'() {
given:
MyAppDao dao = Spy(MyAppDao, constructorArgs: [ dataSource ]) {
getJdbcTemplate() >> Mock(JdbcTemplate) {
1 * query('', null) // ???
}
}
when:
List<Integer> buzzIds = [1, 2, 3, 4]
dao.getFizzByBuzzIds(buzzIds)
then:
1 * dao.jdbcTemplate.query('', null) // ???
}
How can I configure the Spy and the then block label so that executing getFizzByBuzzIds verifies whether the underlying JdbcTemplate.query(...) method is called?
In the example below, I'm attempting to test that the notes text is changed. Is the Assert.AreEqual(note.Text, text); correct?
[TestMethod()]
public void CreateNoteTest_Pass()
{
HomeController target = new HomeController(); // TODO: Initialize to an appropriate value
var note = new NotePM();
string text = "This is my test note" + DateTime.Now;
note.Text = text;
int id = note.NoteId;
note.CreatedByUserName = Membership.GetUser("danielle").UserName;
ActionResult actual;
actual = target.Create(note);
Assert.AreNotEqual(id, note.NoteId);
Assert.IsInstanceOfType(actual, typeof(RedirectToRouteResult));
Assert.AreEqual(note.Text, text);
}
Here's one take on this:
[TestMethod()]
public void EnsureCreateNoteChangesNoteText()
{
string text = "This is my test note" + DateTime.Now;
var note = new NotePM()
{
Text = text;
CreatedByUserName = "danielle";
};
int id = note.NoteId;
ActionResult actual;
HomeController target = new HomeController();
actual = target.Create(note);
Assert.AreNotEqual(id, note.NoteId, "note.NoteID must be assigned by the controller");
Assert.IsInstanceOfType(actual, typeof(RedirectToRouteResult));
Assert.AreNotEqual(text, note.Text, "note.Text must be changed by the controller");
}
Assert.AreNotEqual() is used to check for inequality (and there is a string overload which does a value comparison)
With the asserts which take 2 values, these should be Assert.xxx(Expected, Actual) otherwise the failure message is inverted.
Unit tests should isolate the system under test as far as possible (HomeController in this example). If HomeController is dependent on asp.net Membership ideally, you should inject this to the controller in the constructor to ensure it can be mocked. This way you can ensure that the unit test runs without the need to prep database data, setup connections from the Unit Test runner, etc.
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})
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.