Junit test cases for StreamSupport - java

I am new to test cases I tried several ways to write test case for below piece of code but I never succeeded. How to write junit test case for below code using Powermockito?
StreamSupport.stream(irSet.spliterator(), false)
.filter(iResultRow -> iResultRow !=null)
.mapToInt(iResultRow ->{
String event = iResultRow.get("STF_TY_GH");
return StringUtils.isNotBlank(event) ? Integer.parseInt(event) : 1;
}).findFirst().orElse(1);

While, using a descent amount of mocks you can mock every single call, let me suggest you an alternative approach.
So you have a stream produced out of some input set (irSet) variable. This stream makes "some" processing and returns an integer result.
So if you "imagine" Its a black box: a kind of function that looks like this:
int doSomething(Set<SomeRow> irSet) {
... your implementation is here...
}
In this case, you might want to test what it does by supplying the various input sets and expecting for some outputs. What if there are null-s in the input? Will it fail or filter out what's needed. What if the set is empty? What if there is SomeRow that really has STF_TY_GH data, what if the set doesn't have such a row?
Here is a test for example:
#Test
public void test_rows_with_null_are_processed_correctly() {
// setup:
Set<SomeRow> input = ...// prepare a set with null values
// when:
Integer actual = underTest.doSomething(input)
// then:
// verify this "actual" whether it should be 1 or something else
}
All-in-all, use mocks only for interactions (with something you can't really instantiate like DB API/remote HTTP calls) or for something that is not related to the tested code and is used as a dependency the tested code interacts with. After all, the goal of unit tests is to test your code (the implementation of doSomething in this case and not to mock everything out).

Related

Writing Unittest which takes 2 list

I am a new Junit Learner I would like to test my code according to 2 list class. However I never saw any example of that.
My real code is below :
public static List<JourneyType> applyFilter(List<JourneyType> journeyList, List<AvailabilityFilterOptionType> filterOptions)
{
List<JourneyType> filteredJourneyList = new ArrayList<>();
filteredJourneyList = applyStopFilters(journeyList, filterOptions);
filteredJourneyList = applyCarrierFilters(filteredJourneyList, filterOptions);
filteredJourneyList = applyRbdFilters(filteredJourneyList, filterOptions);
filteredJourneyList = applyDurationFilter(filteredJourneyList, filterOptions);
return filteredJourneyList;
}
and my test scenario :
#Test
public void testApplyFilter()
{
fail("Not yet implemented");
}
Thank you in advanced
Actually, this is pretty simple.
#Test
public void testApplyFilter()
{
assertThat(someObject.applyFilter(journies, filters), is(expectedOutcome));
}
In other words: you know what this method is supposed to do. ( Well, such knowledge is the prerequisite for testing stuff. When you don't know what your code is doing, there is no point in verifying its correctness via testing...)
As in: given some known input data, you should be able put down an expectation about output coming back. And that is what you check for.
Of course, the tricky part could be to correctly identify dependencies, and mock them where needed.
But ideally, your test should just be that: testing the public contract of your method under test. Something goes in, and you check that the output coming back meets your expectations. Ideally, you have to mock nothing for such tests, because you do not at all rely on testing implementation details. You only test the public contract "given this input, this is the expected output".
( where: assertThat() is just a different type of assert, and is() is a hamcrest matcher. There are many other hamcrest matchers, such as containsInAnyOrder() (that one is really neat if you don't care about the order of elements returned, but one has to understand that is used slightly different, it would need containsInAnyOrder(expectedOutcomeList.toArray()) methinks )

PowerMockito verifyNew withArguments of an object and an array of objects

i am trying to test that a method creates an object. i have it almost working using PowerMockito.verifyNew().withArguments() however, the Arguments that are passed to the constructor are an object and an ArrayList of objects. the output of the test is:
Actual
invocationSubstitute.performSubstitutionLogic(
1,
6,
11,
13,
[au.edu.sccs.csp3105.NBookingPlanner.Person#2449cff7],
au.edu.sccs.csp3105.NBookingPlanner.Room#62da83ed,
"description"
);
Expected
invocationSubstitute.performSubstitutionLogic(
1,
6,
11,
13,
[au.edu.sccs.csp3105.NBookingPlanner.Person#40bffbca],
au.edu.sccs.csp3105.NBookingPlanner.Room#42a9a63e,
"description"
);
i can see that the problem is the objects are the same type but not the same object, is there a way of saying the Expected object is of the correct type?
test:
#RunWith(PowerMockRunner.class)
#PrepareForTest({Planner.class, Meeting.class})
public class MonthInput {
Planner planner;
#Rule
public final TextFromStandardInputStream systemInMock = emptyStandardInputStream();
#Rule
public final ExpectedSystemExit exit = ExpectedSystemExit.none();
#SuppressWarnings("deprecation")
#Before
public void setup() throws Exception {
Meeting meetingMock = Mockito.mock(Meeting.class);
PowerMockito.whenNew(Meeting.class).withAnyArguments().thenReturn(meetingMock);
}
#Test
public void MonthInputofless5() throws Exception {
// make spy
planner = Mockito.spy(Planner.class);
//override main menu with do nothing
Mockito.doNothing().when(planner).mainMenu();
//provide inputs
systemInMock.provideLines("1","6","11","13","ML13.218","Mark Colin","done","description");
//set expected outputs
ArrayList<Person> attendees = new ArrayList<Person>();
attendees.add(new Person("Mark Colin"));
Room where = new Room("ML13.218");
//call the method
planner.scheduleMeeting();
//set passing terms
PowerMockito.verifyNew(Meeting.class).withArguments(1,6,11,13,attendees,where,"description");
}
Fix your code
A verify simple fix on your classes: implement hashCode and equals on Person and Room so Powermock verification can actually compare two objects for equality and not just rely on the object reference.
Fix your tests
If you don't want to fix your code, but the test, you could either use a Mockito matcher (i.e. org.mockito.Matchers.eq or org.mockito.Matchers.any). But please note, that eq relies on equals and won't work unless you implement it (see above). But any would match any object of that type (surprise!)
PowerMockito.verifyNew(Meeting.class)
.withArguments(eq(1),eq(6),eq(11),eq(13),
any(List.class),
any(Room.class),
eq("description"));
If the actual value matters, you could use an ArgumentCapture instead of a matcher and check the captured value.
Theoretically, it should look like this:
final ArgumentCaptor<Person> personCaptor = forClass(Person.class);
final ArgumentCaptor<Room> roomCaptor = forClass(Room.class);
PowerMockito.verifyNew(Planner.class)
.withArguments(eq(1),eq(6),eq(11),eq(13),
personCaptor.capture(),
roomCaptor.capture(),
eq("description"));
final Person passedParam = personCaptor.getValue();
//do your comparison here
But I didn't get the capture example running, so maybe that's only possible with plain Mockito.
Just don't!
All that said, you should verify your overall approach. Using Whitebox-Testing may create very brittle tests and won't help much in refactoring and may further foster bad class design.
The imprudent use of Powermockito is an anti-pattern. It's a very mighty tool for testing the untestable, i.e. badly designed legacy code from the dark ages of the internet where the homepages were handcrafted HTMLs and full of wobbly GIFs.
Don't use it for new, greenfield projects. Just don't.
Instead try focusing on the observable result of any action. Invoking the scheduleMeeting() method may produce any result that is more easy to check - it's the result that matters, not the way to get they. Trust me, not a single user gets happier when a constructor was called.
Results could be
an instance of a meeting (as return value, that would be best in your example)
a state change in the planner (any getters?)
a state change in a downstream service / db
a written file
an output written to System.out

How can I unit test that I received correct PreparedStatement?

I want to pass in suitable object into the verify method, not just any().
Is there a way to do it?
I cannot just take and copy Lambda method and pass the results into the verify. That doesn't work because Lambdas cannot be tested directly.
My Unit test which is obviously not even close to testing anything:
#Test
public void testRunTrigger() {
campaignTrigger.updateCampaignStatus();
verify(jdbcTemplate).update(any(PreparedStatementCreator.class));
assertEquals("UPDATE campaign SET state = 'FINISHED' WHERE state IN ('PAUSED','CREATED','RUNNING') AND campaign_end < ? ", campaignTrigger.UPDATE_CAMPAIGN_SQL);
}
And this is the class I'm testing :
#Component
#Slf4j
public class CampaignTrigger {
final String UPDATE_CAMPAIGN_SQL = String.format("UPDATE campaign SET state = '%s' " +
" WHERE state IN (%s) AND campaign_end < ? ", FINISHED,
Stream.of(PAUSED, CREATED, RUNNING)
.map(CampaignState::name)
.collect(Collectors.joining("','", "'", "'")));
#Autowired
private JdbcTemplate jdbcTemplate;
#Scheduled(cron = "${lotto.triggers.campaign}")
#Timed
void updateCampaignStatus() {
jdbcTemplate.update(con -> {
PreparedStatement callableStatement = con.prepareStatement(UPDATE_CAMPAIGN_SQL);
callableStatement.setTimestamp(1, Timestamp.valueOf(LocalDateTime.now()));
log.debug("Updating campaigns statuses.");
return callableStatement;
});
}
Any advice, or theoretical knowledge that this is not the way to do it I would highly appreciate.
You shouldn't mock the code which you don't control. Mock only the code for which you have your tests, because when mocking you are assuming that you know (i.e. you define) how the mocked class works.
Here, you have no idea how jdbcTemplate works and whether calling it with some lambda actually does what you think it does.
Testing your code with code that you don't control is the point of integration tests. I.e. you should test your CampaignTrigger together with a real database (or in-memory one) and without mocking jdbcTemplate.
You could try your luck with capturing the object that is used for that call, see here. That allows to write code like this:
ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
verify(mock).doSomething(argument.capture());
assertEquals("John", argument.getValue().getName());
Giving you full access to the object that was passed to your method call! And note that mockito recently introduced a #Captor annotation that makes things even easier to use.
Edit; given the comments by #Morfic: what he states is absolutely reasonable.
This answer is giving the "immediate" hint how you could solve that specific problem.
Beyond: the reasonable approach is always always always to slice that "unit under test" ... to be as small as possible!
Your class/method(s) should serve exactly one responsibility; and then you makes sure that the implementation can be tested with most simple means possible.
So: if the question is: "should I use argument captors or should I better rework my production code" - then rework your production code.

What methods should I have JUnit tests for - How to mock methods with many dependencies

I am new to JUnit, and do not know which methods should have tests and which should not. Take the following example:
public List<Site> getSites(String user)
{
SiteDao dao = new SiteDaoImpl();
List<Site> siteList = new ArrayList<Site>();
ServiceRequest rq = new ServiceRequest();
rq.setUser(user);
try
{
ServiceResponse response = siteDAO.getReponse(rq);
List<String> siteNums = response.getSiteNums();
if (siteNums != null && !siteNums.isEmpty())
{
List<DbModelSite> siteInfo = dao.getSiteInfo(siteNums);
if (siteInfo != null && !siteInfo.isEmpty())
{
siteList = SiteMapper.mapSites(siteInfo);
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
return siteList;
}
public static List<Site> mapSites(List<DbModelSite> siteInfo)
{
List<Site> siteList = null;
if (siteInfo != null && !siteInfo.isEmpty())
{
siteList = new ArrayList<Site>();
for (DbModelSite temp : siteInfo)
{
Site currSite = mapSite(temp);
siteList.add(currSite);
}
}
return siteList;
}
public static Site mapSite(DbModelSite site)
{
Site mappedSite = null;
if (site != null)
{
mappedSite = new Site();
mappedSite.setSiteNum(site.getSiteNum());
mappedSite.setSpace(site.getSpace());
mappedSite.setIndicator("Y");
}
return mappedSite;
}
It is pretty trivial to come up with a unit test for both the mapSites() and mapSite()methods, but where I am having trouble is with the getSites() method. Does it make sense to unit test this method? If so, how would I go about doing so? It seems that this would require quite a bit of mocking, and as I am very new to JUnit, I have not been able to figure out how to mock all of these objects.
So my question is really two fold:
How do you determine if a method needs to be unit tested?
How does one unit test a complex method which requires a large amount of mocking?
Yes, it makes sense to test that method.
The first thing to be able to test it, would be to use dependency injection. If the method creates its own SiteDao instance using new, there is no way you can tell the method to use another, mock instance of SiteDao.
So, read on dependency injection, and use it. Basically, it boils down to
public class MyService {
private SiteDao siteDao;
public MyService(SiteDao siteDao) {
this.siteDao = siteDao;
}
// use the siteDao passed when constructing the object, instead of constructing it
}
That way, when testing your service, you can do
SiteDao mockSiteDao = mock(SiteDao.class);
SiteService service = new SiteService(mockSiteDao);
Here's one pice of advice that is not directly related to your question, but will make your code much simpler, and thus easier to test, too:
Never return null from a method returning a collection. Return an empty collection to signal "no element".
In general, don't accept null as a valid method argument value, especially if the argument is a collection.
Corollary of 1 and 2: by following these principles, you never need to check for null or emptyness of a collection. Just use it directly.
This will reduce the number of if (siteNums != null && !siteNums.isEmpty()) cluttering your code, and you'll have way fewer branches to test, too.
Note that all sane libraries (the JDK methods, JPA, etc.) follow these principles. A JPA query will never return a null list for example.
Also, don't swallow an exception by just printing its stack trace and returning an empty list, as if nothing bad happened. Let the exception propagate so that you can notice and fix the bug.
Just imagine that this method is a method returning the number of cancer tumors found by a medical analysis system. Would you really like the system to tell you that you're in perfect health, whereas the system was in fact unable to do its job due to an exception? I would really prefer the system to say "I'm out of order, use another machine to be sure".
The idea of unit testing is to ensure that each "unit" (which is usually a method) can be tested in isolation so you can test that for given input you receive an expected output, so to answer your questions:
I should say all public methods should be unit tested
If you are doing too much in your method that you need to mock lots then you probably want to break the functionality out into another class
Going back to your example there are a couple of things to be wary of if you want to unit test:
new - anytime you use this keyword in a method you will find it difficult to mock that object. In some cases (like ServiceRequest) it's fine but in others such as SiteDao you'll have problems.
Static methods - same thing, with SiteMapper.mapSites(siteInfo) you will find it difficult to mock
You can use libraries such as PowerMock to mock new, private and static methods but I personally try to avoid that.

How to test a the retrieve method of my class without testing the insert in the same testcase?

I am learning unit tests (in a TDD-like approach).
I am creating a class that encapsulates an collection, it has 3 methods:
store
retrieveAllDocuments
hasItem
I created one test: testRetrieveWhenEmpty, whici goes like this:
#Test
public void testRetrieveAllDocumentsWhenEmpty() {
List<String> storedDocs = state.retrieveAllDocs();
assertNotNull(storedDocs);
assertEquals(0, storedDocs.size());
}
And then I made it pass.
Now I would like to create a testRetrieveAllDocumentsWhenNotEmpty, which would be like this:
#Test
public void testRetrieveAllDocumentsWhenNotEmpty() {
state.store("test") //This is the only api point that I can use to insert things
List<String> storedDocs = state.retrieveAllDocs();
assertNotNull(storedDocs);
assertEquals(1, storedDocs.size());
assertEquals("test", storedDocs..get(0));
}
But now I have to implement the store method, so I created the following test method:
#Test
public void testStoreDocument() {
state.store("test")
List<String> storedDocs = state.retrieveAllDocs(); //This is the only api point I can use to see the content
assertNotNull(storedDocs);
assertEquals(1, storedDocs.size());
assertEquals("test", storedDocs.get(0));
}
I see two problems:
These methods are identical.
I test two methods in each test, if the store fails, I get a message that the retrieve has a problem.
Using reflection would bind my test to my implementation, and I am trying to avoid it.
Changing the interface for better testing is hard to argument to my team mates.
What approach do you take in these cases? (Is this case a problem at all?)
You could try shifting your view from writing "a (set of) tests per method" to "a test per useful behaviour" of the class you are testing.
If this class is both reader and writer of the data, it kinda makes sense to use its insert operations when testing the retrieval behaviour and vice versa.
I'd test the no items, one item, multiple items, has a specific item, does not have a specific item cases. These tests would implicitly test the store method as well.
Kevlin Henney's talk programming with GUTs provides a good explanation about this concept.
Actually does not need to be equals:
In testRetrieveAllDocumentsWhenNotEmpty you can add more than one document then check size, also you don't need to get all individual documents, you need to assert size is the correct.
This method asserts to get ALL documents in a non empty scenario, if you can assert you inserted 3, AND as long the testStoreDocument exists, you don't need to assert the document retrieve but yes the list size to know if ALL are returned.
#Test
public void testRetrieveAllDocumentsWhenNotEmpty() {
state.store("test1")
state.store("test2")
state.store("test3")
List<String> storedDocs = state.retrieveAllDocs();
assertNotNull(storedDocs);
assertEquals(3, storedDocs.size());
}
In testStoreDocument, you need to get the document, you don't need to assert the size of stored documents.
#Test
public void testStoreDocument() {
state.store("test")
List<String> storedDocs = state.retrieveAllDocs(); //This is the only api point I can use to see the content
assertNotNull(storedDocs);
assertEquals("test", storedDocs.get(0));
}
As mention before try to write your unit tests in a way they test scenarios. Every reader understands then better what you class is for. Since we do not just want to use a method, we want to achieve something with this method.
You can express this in the name of your tests like this: when{SomethingHappens}Then{ThisIsExpected} or given{Situation}Should{BeHandledInThisWay}
You could create tests like givenStoredDocumentsShouldBeAllReturned and whenDocumentIsStoredThenItCanBeRetrieved

Categories