I have a below test class method that I am writing a test for.
public String doSomething(Dependency dep) {
StringBuilder content = new StringBuilder();
String response;
while ((response = dep.get()) != null) {
content.append(response);
}
return content.toString();
}
Below is the test case I have. Basically I want the Dependency#get() method to return "content" in the first iteration and null in the second.
#Test
void test(#Mocked Dependency dep) {
new Expectations() {
{
dep.get();
result = "content";
times = 1;
}
};
Assertions.assertEquals("content", testSubject.doSomething(dep));
}
However this results in JMockit throwing Unexpected invocation to: Dependency#get() error. If I remove the times field, my test runs in a forever loop.
How can I test this method?
So I found out that JMockit apart from the result paramater can also set a returns(args...) method to which we can pass a series of arguments that it will expect sequentially. So modifying the test to this worked for me.
#Test
void test(#Mocked Dependency dep) {
new Expectations() {
{
dep.get();
returns("content", null);
times = 2; // limiting to mock only twice as only 2 values are provided in returns
}
};
Assertions.assertEquals("content", testSubject.doSomething(dep));
}
Related
I am extracting concept from a single page and that page is being used in different functions, so i have created a function that assigns the value if value hasn't been assigned yet.
public String text() {
if (text.isPresent()) {
return text.get();
}
this.text = Optional.of(extractText(pdDocument));
return text.get();
}
I would like to create a test that checks that the function is being called once and the context is shared between the functions that doing some functionality in the same context
Here is an example when text() is being called twice
private Optional<String> packingListNet() {
return locatePattern(text(), PACKING_LIST_NET);
}
private Optional<String> packingListNumber() {
return locatePattern(text(), PACKING_LIST_NUMBER);
}
Would be grateful for any information, thank you
The technical answer: you could use a mocking library, such as PowerMockito, to create mocked instances of the Optional class. And when you have a mock object, you can instruct the mock how to react to method calls. Then you need to "get" the mocked Optional object into your class under test.
You could use that to cover the first if statement: you expect the mock to see the isPresent() call, to return true, and to then return a specific string. Your testcase could then check "that expected string came back". Similar for the other way round, when the mocked Optional "is empty", then you ensure another string is returned, and you check for that.
But honestly, it is doubtful if you should do that all.
You should focus on the public contract that your method there provides.
And that would mean:
Enable yourself that you can pass in a (real) Optional object into the class under test
When your Optional is not empty, your test expects ... what you put into it
When your Optional is empty, your test expects whatever extractText() will return
Of course, mocking is really problematic here: Optional is a final class. So you need to either use Mockito with "experimental support for final enabled", or you need to use PowerMock(ito) (which I strongly advise to never use).
So, as said: avoid mocking.
I think this method is badly conceived. It may rely on private, mutable state that will be a problem with multiple documents and threads accessing them.
A better approach would be to pass all the necessary information as method parameters. They are thread safe that way;
public static String getText(String textToSearchFor, Document pdfDocument) {
// extract here
}
Here's how I might write a JUnit test for a method like this:
public class TextMethodOwnerTest {
#Test
public void testGetText_Success() {
// setup
String expected = "text to find";
Document pdf; // Have to get this.
// exercise
String actual = TextMethodOwner.getText(expected, pdf);
// assert
Assert.assertEquals(expected, actual);
}
#Test
public void testGetText_PackingListNumber() {
// Add another case here
}
#Test
public void testGetText_PackingListNet() {
// Add another case here
}
}
I am not sure what are you trying to ask. Information is not clear but maybe this can help you:
Junit and mockito are mostly used togther. If you want to check any function gets called only one time we use verify() method of mockito with parameter atLeast(1)
For example: Example taken from (https://www.baeldung.com/mockito-verify)
List<String> mockedList = mock(MyList.class);
mockedList.clear();
mockedList.clear();
mockedList.clear();
verify(mockedList, atLeast(1)).clear();
Here is some pseudo code how you could achieve it:
public Class {
int counter = 0;
void test() {
counter++;
}
}
public ClassTest {
public Class class;
void shouldBeCalledOneTime() {
class.test();
AssertThat(class).hasFieldWithValue("counter", 1);
}
}
Since your question seemed to me mostly about reading the file only once, which is quite a genuine need for many, I wrote up this class using your code, but without JUnit.
This has a main method that calls the packingList*() method 100 times to different threads, but you will see that the extraction part is entered into only once in the beginning. For this, I have added a lock and used a synchronized block. I understand that this is basic, but thought I may share since it might help others.
Note the changes in the method public String text().
public class ReusedText{
private static final long PACKING_LIST_NET = 200;
private static final long PACKING_LIST_NUMBER = 120;
private Optional<String> text = Optional.ofNullable( null );
private Document pdDocument;
private static final Object LOCK = new Object();
private static final ExecutorService svc = Executors.newFixedThreadPool( 2 );
public ReusedText(Document pdDocument) {
super();
this.pdDocument = pdDocument;
}
public static void main( String[] args ){
ReusedText rt = new ReusedText( new Document( "/path/to/document/on/disk" ) );
for( int i = 0; i < 100; i++ ) {
svc.submit( () -> System.out.println( rt.packingListNet() ) );
svc.submit( () -> System.out.println( rt.packingListNumber() ) );
}
svc.shutdown();
}
public String text() {
if (text.isPresent()) {
return text.get();
}
else {
synchronized (LOCK) {
/* This repeated 'if' block is necessary because 'text' may have got populated while this thread was waiting for lock. */
if (text.isPresent()) return text.get();
else{
System.out.println( "Extracting text..." );
this.text = Optional.of( extractText( pdDocument ) );
return text.get();
}
}
}
}
private String extractText( Document doc ) {
//Read the file contents using some API like java.nio.file.Files or Apache Tika
return "file contents here!";
}
private Optional<String> packingListNet() {
return locatePattern(text(), PACKING_LIST_NET);
}
private Optional<String> packingListNumber() {
return locatePattern(text(), PACKING_LIST_NUMBER);
}
private Optional<String> locatePattern( String text, long packingListNumber ){
//Implement your logic with the text here.
return Optional.of( String.valueOf( packingListNumber ) );
}
private static class Document{
private String pathToText;
public Document(String pathToText) {
super();
this.pathToText = pathToText;
}
public String getPathToText(){
return pathToText;
}
}
}
I'm having problems with two void methods. In encouragedVenturesScoring I've followed this answer mocking an arraylist that will be looped in a for loop and haven't mocked the list, but passed a real list and added mocked objects.
Mockito gives me an InvalidUseOfMatchersException on this line
verify(effectList.get(Mockito.anyInt())).execute(playerHandler);
There are lots of questions on SO on this exception , and I think it's because of anyInt(). Anyway I changed it to
verify(effectList.get(0)).execute(playerHandler);
And now it's saying Wanted but not invoked effect.execute(playerHandler)
Actually there were zero interactions with this mock
Is it because I put doNothing ?
doNothing().when(effect).execute(playerHandler);
In my second method militaryStrengthScoring() method is there a way to skip the first chunk of code and just test the if..else condition? What would be the best approach to test this method?
Thank you for your time.
This is the class to be tested
public class EndGameScoringBaseController implements EndGameScoringHandler {
private static final int[] TERRITORIES_REWARD = {0,0,1,4,10,20};
private static final int[] CHARACTERS_REWARD = {1,3,6,10,15,21};
private static final int RESOURCES_RATE = 5;
private static final int FIRST_MILITARY_REWARD = 5;
private static final int SECOND_MILITARY_REWARD = 2;
private PlayerHandler player;
public EndGameScoringBaseController(PlayerHandler player) {
super();
this.player = player;
}
#Override
public void encouragedVenturesScoring() {
for (DevelopmentCard card : player.getPlayer().getPersonalBoard().getVentures()) {
for (Effect e : card.getPermanentEffects())
e.execute(player);
}
}
#Override
public void militaryStrengthScoring(GameController game) {
Set<Integer> points = new HashSet<>();
int myPoints = this.player.getPointsHandler().getMilitaryPoints();
for (PlayerHandler p: game.getPlayers()) {
points.add(p.getPointsHandler().getMilitaryPoints());
}
int[] rank = new int[points.size()];
int j = 0;
for (Integer i : points) {
rank[j] = i;
j++;
}
Arrays.sort(rank);
if (rank[rank.length-1] == myPoints) {
player.getPointsHandler().winMilitaryPoints(FIRST_MILITARY_REWARD);
}
else if (rank[rank.length-2] == myPoints) {
player.getPointsHandler().winVictoryPoints(SECOND_MILITARY_REWARD);
}
}
Tested method for encouragedVenturesScoring
#Test
public void encouragedVenturesScoringTest() {
//given
List<DevelopmentCard> ventureList;
ventureList = Arrays.asList(developmentCard, developmentCard);
when(playerHandler.getPlayer().getPersonalBoard().getVentures()).thenReturn(ventureList);
List<Effect> effectList;
effectList = Arrays.asList(effect, effect);
when(developmentCard.getPermanentEffects()).thenReturn(effectList);
doNothing().when(effect).execute(playerHandler);
//when
endgameController.encouragedVenturesScoring();
//then
verify(effectList.get(Mockito.anyInt())).execute(playerHandler);
}
Incomplete tested method for militaryStrengthScoring
#Test
public void militaryStrengthScoringTest() {
//given
when(playerHandler.getPointsHandler().getMilitaryPoints()).thenReturn(4);
doNothing().when(playerHandler.getPointsHandler()).winMilitaryPoints(FIRST_MILITARY_REWARD);
//when
endgameController.militaryStrengthScoring(gameController);
//then
/../
}
You're right that this is the problem:
verify(effectList.get(Mockito.anyInt())).execute(playerHandler);
Mockito only allows for calls like any() and anyInt() to stand in for parameters to the mock themselves, due to the internal implementation of matchers.
/* OK */ when(yourMock.yourMethod(anyInt())).thenReturn(42);
/* BAD */ when(yourList.get(anyInt()).yourMethod(0)).thenReturn(42);
/* OK */ verify(yourMock).yourMethod(anyInt());
/* BAD */ verify(yourList.get(anyInt())).yourMethod(0);
The failure with get(0) is likely an actual failure, and may be related to the fact that your encouragedVenturesScoringTest is actually not calling encouragedVenturesScoring, it's calling influencedCharactersScoring. If this continues to give you trouble after fixing that error, in ways related to Mockito, please edit your question.
You can only verify mock objects created by Mockito.
But effectList is a "real" list. Therefore Mockito knows nothing about that object. Thus any attempt to verify that list must fail.
If you want to verify that object - then you have to mock it!
Of course, this means that you have specify all calls that will go to the mocked list.
I'm using Mockito to mock a method to return a Date when given a Date.
when(supplier.calculateDeliveryDate(any(Date.class)))
.thenReturn(supplierDeliveryDate);
However, I only want it to return the supplierDeliveryDate when it is passed a non-null Date object.
When passed null, it should return null.
Is this possible? How can I do it?
Use ArgumentMatchers.isNull() matcher.
when(supplier.calculateDeliveryDate(any(Date.class)))
.thenReturn(supplierDeliveryDate);
when(supplier.calculateDeliveryDate(isNull()))
.thenReturn(null);
You could use an anonymous inner class:
// unit test
public OrderServiceTest {
// instance of class-under-test
private OrderService instance;
// stub value
private Date supplierDeliveryDate = new Date();
// mock as an anonymous inner class
private Supplier supplier = new Supplier() {
public Date calculateDeliveryDate(Date input) {
if (input == null) {
return null;
}
else {
return supplierDeliveryDate;
}
}
};
#Before
public void setUp() {
instance = new OrderService();
// dependency injection
instance.setSupplier(supplier);
}
#Test
public void testOrderHappy() {
// SETUP
Date orderDate = new Date();
// CALL
Date result = instance.order(orderDate);
// VERIFY
assertTrue(supplierDeliveryDate == result);
}
#Test
public void testOrderNull() {
// SETUP
Date orderDate = null;
// CALL
Date result = instance.order(orderDate);
// VERIFY
assertNull(result);
}
}
But you should really wonder why you need this kind of behavior.
If you write a well defined test case then you should know exactly how often, and with which arguments, your mock is called. If so, then you can just stub the expected calls instead of wiring your mock with conditional behavior.
Note that is is useful if your test is as 'sharp' as possible. If a different number of calls hits your mock than expected, or with different arguments, then the test should fail.
You can use helper method:
public static <T> void validateAndMock(Supplier<T> ongoingStubbing, T mockedResponse) {
if (mockedResponse != null) {
when(ongoingStubbing.get()).thenReturn(mockedResponse);
}
}
And then call:
validateAndMock(() -> supplier.calculateDeliveryDate(any(Date.class)), supplierDeliveryDate);
My first method is simple, its just a toString which outputs 3 class specific fields
public String toString(){
return String.format("%s/%s/%s",street,city,postcode);
}
In JUnit it gives me this to form the tests on, I am unsure how to do this efficiently.
#Test
public void testToString() {
System.out.println("toString");
Address instance = null;
String expResult = "";
String result = instance.toString();
assertEquals(expResult, result);
// TODO review the generated test code and remove the default call to fail.
fail("The test case is a prototype.");
}
I have done lots of research on JUnit and understand the concept of testing but can't quite get my head around how to do it with my code. Also how would I test this method efficiently, this is a method in a subclass which is the abstract method in the parent class
#Override
int getDiscountRate() {
return this.companyDiscount;
}
It gives me this to test
#Test
public void testGetDiscountRate() {
System.out.println("getDiscountRate");
BusinessOrganisationDetails instance = null;
int expResult = 0;
int result = instance.getDiscountRate();
assertEquals(expResult, result);
// TODO review the generated test code and remove the default call to fail.
fail("The test case is a prototype.");
}
This looks good. Of course, you need to instanciate the instance variables, else it will result in a NullPointerException.
Here, how it could look like in the end:
#Test
public void testToString() {
System.out.println("toString");
Address instance = new Address();
instance.setStreet("Somestreet");
instance.setCity("Somecity");
instance.setPostcode("12345");
String expResult = "SomestreetSomecity12345";
String result = instance.toString();
assertEquals(expResult, result);
}
And the other test:
#Test
public void testGetDiscountRate() {
System.out.println("getDiscountRate");
BusinessOrganisationDetails instance = new BusinessOrganisationDetails();
instance.setCompanyDiscount(50);
int expResult = 50;
int result = instance.getDiscountRate();
assertEquals(expResult, result);
}
I have my existing framework built up using Jfunc which provides a facility to continue exection even when one of the asserts in the test case fails. Jfunc uses junit 3.x framework. But now we are migrating to junit4 so I can't use Jfunc anymore and have replaced it with junit 4.10 jar.
Now the problem is since we have extensively used jfunc in our framework, and with junit 4 we want to make our code continue the execution even when one of the asserts fails in a test case.
Does anyone has any suggestion/idea for this, i know in junit the tests needs to be more atomic i.e. one assert per test case but we can't do that in our framework for some reason.
You can do this using an ErrorCollector rule.
To use it, first add the rule as a field in your test class:
public class MyTest {
#Rule
public ErrorCollector collector = new ErrorCollector();
//...tests...
}
Then replace your asserts with calls to collector.checkThat(...).
e.g.
#Test
public void myTest() {
collector.checkThat("a", equalTo("b"));
collector.checkThat(1, equalTo(2));
}
I use the ErrorCollector too but also use assertThat and place them in a try catch block.
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.*;
#Rule
public ErrorCollector collector = new ErrorCollector();
#Test
public void calculatedValueShouldEqualExpected() {
try {
assertThat(calculatedValue(), is(expected));
} catch (Throwable t) {
collector.addError(t);
// do something
}
}
You can also use assertj - soft assertion
#Test
public void testCollectErrors(){
SoftAssertions softly = new SoftAssertions();
softly.assertThat(true).isFalse();
softly.assertThat(false).isTrue();
// Don't forget to call SoftAssertions global verification !
softly.assertAll();
}
Also exist other way to use it without manually invoke softly.assertAll();
with rule
with autoclosable
Using the static assertSoftly method
Use try/finally blocks. This worked in my case:
...
try {
assert(...)
} finally {
// code to be executed after assert
}
...
Try - catch, in "try" use the assertion, in "catch" add the possible error to collection.
Then throw the exception at the end of test, in tearDown().
So if there will be fail/error in assert, it will be catched and test will continue.
(The collection in example is static, you can also make new instance in setUp() for each #Test)
public static List<String> errors = new ArrayList<>();
try {
//some assert...
}
catch (AssertionError error) {
errors.add(error.toString());
}
#After
public void tearDown() {
try {
if (!errors.isEmpty()) {
throw new AssertionError(errors);
}
}
finally {
//empty list because it's static, alternatively make instance for each test in setUp()
errors.clear();
}
}
I created my own simple assertions class. Easy to extend with your use-cases:
public class MyEquals {
public static void checkTestSummary(MyTestSummary myTestSummary) {
final List<MyTestResult> conditions = myTestSummary.getTestResults();
final int total = conditions.size();
final boolean isSuccessful = myTestSummary.isSuccessful();
if (isSuccessful) {
System.out.println(format("All [%s] conditions are successful!", total));
} else {
final List<MyTestResult> failedConditions = conditions.stream().filter(MyTestResult::isTestResult).collect(Collectors.toList());
System.out.println(format("\nNot yet.. [%s out of %s] conditions are failed", failedConditions.size(), total));
}
if (!isSuccessful) {
for (int i = 0; i < total; i++) {
final MyTestResult myTestResult = conditions.get(i);
if (myTestResult.isTestResult()) {
System.out.println(format(" Success [%s of %s] => Expected %s Actual %s Good!", i + 1, total, myTestResult.getExpected(), myTestResult.getActual()));
} else {
System.out.println(format("!! Failed [%s of %s] => Expected %s Actual %s", i + 1, total, myTestResult.getExpected(), myTestResult.getActual()));
}
}
}
assertTrue(isSuccessful);
}
public static void myAssertEquals(MyTestSummary myTestSummary, Object expected, Object actual) {
if (checkEquals(expected, actual)) {
assertEquals(expected, actual);
myTestSummary.addSuccessfulResult(expected, actual);
} else {
myTestSummary.addFailedResult(expected, actual);
myTestSummary.setSuccessful(false);
}
}
public static boolean checkEquals(Object value1, Object value2) {
if (value1 == null && value2 == null) {
return true;
} else if (value1 != null && value2 == null) {
return false;
} else if (value1 == null && value2 != null) {
return false;
} else if (value1 != null && value2 != null) {
return value1.equals(value2);
}
return false;
}
}
#Builder
#Value
public class MyTestResult {
String expected;
String actual;
boolean testResult;
}
#Data
public class MyTestSummary {
private boolean successful = true;
private List<MyTestResult> testResults = new ArrayList<>();
public MyTestSummary() {
}
public void addSuccessfulResult(Object expected, Object actual) {
getTestResults().add(MyTestResult.builder()
.expected(String.valueOf(expected))
.actual(String.valueOf(actual))
.testResult(true)
.build()
);
}
public void addFailedResult(Object expected, Object actual) {
getTestResults().add(MyTestResult.builder()
.expected(String.valueOf(expected))
.actual(String.valueOf(actual))
.testResult(false)
.build()
);
}
}
Usage in the junit test
#Test
public void testThat() {
MyTestSummary myTestSummary = new MyTestSummary();
myAssertEquals(myTestSummary, 10, 5 + 5);
myAssertEquals(myTestSummary, "xxx", "x" + "x");
checkTestSummary(myTestSummary);
}
Output:
Not yet.. [1 out of 2] conditions are failed
Success [1 of 2] => Expected 10 Actual 10 Good!
!! Failed [2 of 2] => Expected xxx Actual xx
org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
Expected :true
Actual :false
Another option is the observable pattern in conjunction with lambda expressions. You can use something like the above.
public class MyTestClass {
private final List<Consumer<MyTestClass>> AFTER_EVENT = new ArrayList<>();
#After
public void tearDown() {
AFTER_EVENT.stream().forEach(c -> c.accept(this));
}
#Test
public void testCase() {
//=> Arrange
AFTER_EVENT.add((o) -> {
// do something after an assertion fail.
}));
//=> Act
//=> Assert
Assert.assertTrue(false);
}
}