I am using the JOptionPane.showInputDialog call in my code.
When the junit tests run it pops up the window.
Is there a way to suppress the pop-up?
Wold mocking it help?
Please help me on this.
I know - this question is ancient. But maybe sometimes someone will have the same problem...
Remember: It's your code, isn't it? So you can easily refactor from
public boolean myMethod() {
String value = "NOTHING";
if(this.someCondition) {
value = JOptionPane.showInputDialog(...);
}
return "NOTHING".equals(value);
}
to
public boolean myMethod() {
String value = "NOTHING";
if(this.someCondition) {
value = getValueFromDialog();
}
return "NOTHING".equals(value);
}
protected getValueFromDialog() {
return JOptionPane.showInputDialog(...)
}
This done, you can write a test mocking away the actual invocation of JOptionPane (Example uses Mockito syntax)
#Test
public void test_myMethod() {
MyClass toTest = mock(MyClass.class);
//Call real method we want to test
when(toTest.myMethod()).doCallRealMethod();
//Mock away JOptionPane
when(toTest.getValueFromDialog()).thenReturn("HELLO JUNIT");
//Perform actual test code
assertFalse(toTest.myMethod());
}
All done - now add tests simulating all the funny stuff that might happen as a result of JOptionPane.showInputDialog() (returning null, returning unexpected values...) by simply adding test cases and different values for
when(toTest.getValueFromDialog()).thenReturn(...);
Related
I have my ServiveImpl class, which has public methods to create and delete index from AEM to Solr. How can we handle the Junit for these void methods using Mockito? Any pointers will be help. Mainly for testing integration with Solr
In this case, your JUnit wouldn't really make any difference other than giving you some test coverage.
The reason behind writing a Junit is to ensure that a method returns a result, or throws an exception. With a void method, the only thing that can be tested is that the method executes.
To solve this, it would be good to at least return a boolean value. Without this, you can never be sure whether the index was really deleted or not.
So the suggestion here would be-
Update the method to ensure the correct error handling takes place.
Based on the method execution, return a boolean value at least. This will not have any impact on your project because the method was void anyway and no calls would be impacted.
In your Junit, assert the returned value as true or false, or just use the assertTrue method.
boolean deleteIndex(String indexName) {
if (deleted) {
return true;
} else {
return false;
}
}
JUnit-
#InjectMocks
private ServiveImpl service = new ServiveImpl();
#Test
public void testIndexDeletion() {
boolean indexDeleted = ServiveImpl.deleteIndex("someIndex");
assertTrue(indexDeleted);
}
I would like to ask for a help and suggestions what is a correct approach in my case (probably its easy but I'm just starting with JUnit). Here is a part of my code
public boolean arrayListEmpty()
{
if(numericalSequence.isEmpty() == true)
return true;
else
return false;
}
This is a public method from model which I suppose i should test, it's just returning true if my numericalsequence is empty as you can see. I cant check it directly invoking numericalSequence.isEmpty (in controller where I need it) because it is private.
So obvious thing is to check
assertEquals(true, test.arrayListEmpty());
So my question is about suggestions what other asserts should I use/what cases should I predict which can come out. Should I in Test method fill numericalSequence with some values and assert it also? (for me its not necessary because any value inserted into sequence = not null but maybe it is not so easy)
First of all, welcome to Stack Overflow!
Looking at your question, it sounds like you're new to unit-testing (correct me if I'm wrong). So, I'll break my answers in to two sections; (1) answering your question, and (2) to give a general direction of how to write good tests and testable classes.
1. Answering your question
There are a couple more use cases you can think of here:
What happens if numericalSequence is null?
What if numericalSequence has 1 element?
What if numericalSequence has a null element?
Some of the cases above may not be possible depending on how your class is set up, but it's a test worth having so that any changes to the class that violates the "previously agreed behavior" of one of these test cases would fail.
2. Writing good tests
There are no strict guidelines on what to do in order to write good tests, however, if you structure your code to be testable, you'll find that writing good tests becomes easier, and would be less of chore. Allow me to explain.
NOTE: This is not a comprehensive guide, but is meant to start your journey in to the path of how to write better code, and better tests
So assume a class that needs to be tested is written like this:
class MyClass {
// NOTE: This is not `final`
private List<Integer> numericalSequence;
public MyClass() {
this.numericalSequence = new ArrayList<>();
}
public void doSomething(Integer x) {
if (x < 0) {
numericalSequence = new ArrayList<>();
} else {
numericalSequence.add(2 * x);
}
}
public boolean arrayListEmpty() {
// NOTE: Your sample code can be reduced to this one-liner
return numericalSequence.isEmpty();
}
}
Here are some of the flaws in the above code:
doSomething method allows nullable (boxed integer) values and so can cause NullPointerException in the first if statement.
The numericalSequence member is not final and hence the code that sets it to null is valid inside the doSomething method
The arrayListIsEmpty method does not check if numericalSequence is null
If I want to test how arrayListIsEmpty behaves when numericalSequence is null, or has null elements, it is hard to do so, unless you know how to get the class to that state.
If the class was re-written to the following:
class MyClass {
private final List<Integer> numericalSequence;
public MyClass() {
this(new ArrayList<>());
}
// Should be made public only if the classes that use this one needs to
// initialize this instance with the sequence. Make this package-private
// otherwise.
public MyClass(List<Integer> sequence) {
this.numericalSequence = sequence;
}
public void doSomething(int x) {
if (x < 0) {
// COMPILE ERROR: Cannot assign to a final member
// numericalSequence = new ArrayList<>();
numericalSequence.clear();
} else {
numericalSequence.add(2 * x);
}
}
public boolean arrayListEmpty() {
return numericalSequence == null || numericalSequence.isEmpty();
}
}
A few things to note about the above structure:
There are two constructors; the default invokes the one that takes a list of integers as the sequence, so that it reuses any logic that both would need to share. There are no logic in this example, but hopefully you'll come across one soon.
The doSomething() method doesn't accept Integer value, but int value that makes sure that x is never null (Java numerical primitive types cannot be null). This also means, numericalSequence cannot contain null values through doSomething().
Since numericalSequence can be initialized from outside of this class, the arrayListEmpty() method makes sure to check that numericalSequence is either null is truly empty.
Now you can write test cases like so:
#Test
public void arrayListEmpty_WhenListIsNull() {
MyClass test = MyClass(null);
assertTrue(test.arrayListEmpty());
}
#Test
public void arrayListEmpty_WhenListIsEmpty() {
MyClass test = MyClass();
assertTrue(test.arrayListEmpty());
}
#Test
public void arrayListEmpty_WhenListHasOnlyOneNonNullElement() {
List<Integer> sequence = new ArrayList<>();
sequence.add(0);
MyClass test = new MyClass(sequence);
assertFalse(test.arrayListEmpty());
}
#Test
public void arrayListEmpty_WhenListHasOnlyOneNullElement() {
List<Integer> sequence = new ArrayList<>();
sequence.add(null);
MyClass test = new MyClass(sequence);
assertFalse(test.arrayListEmpty());
}
Since doSomething() adds/clears the sequence, when writing tests for doSomething() make sure the call and verify the state of the class by checking the return value of arrayListEmpty().
For example:
#Test
public void doSomething_WhenInputLessThanZero() {
List<Integer> sequence = new ArrayList<>();
sequence.add(0);
MyClass test = new MyClass(sequence);
test.doSomething(-1);
assertTrue(test.arrayListEmpty());
}
My intention was to show a couple of things:
Structure your tests cases to be small and concise
Design your class to be easily testable
Hope this helps.
I'm using a Calendar object to determine whether or not to increase the workload of a system based on current day/hour values. Given that this object uses static methods, I'm using PowerMock to mock the static methods with the following annotations:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ Calendar.class })
The code under test is pretty simple (though my logic needs work, I know):
public void determineDefaultMaximumScans() throws ParseException{
parseTime();
Calendar cal = Calendar.getInstance();
int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
System.out.println(cal.get(Calendar.DAY_OF_WEEK));
if(dayOfWeek == (Calendar.SATURDAY) || dayOfWeek == (Calendar.SUNDAY)){
setDefaultMax(calculateNewDefaultMax(getDefaultMax()));
System.out.println("defaultMax increased by 20%");
} else {
if(currentTime.after(afterHoursBegin) && currentTime.before(afterHoursEnd)){
System.out.println("Not afterhours. Maintaining current maximum.");
setDefaultMax(defaultMax);
System.out.println("Current Maximum number of scans: " + getDefaultMax());
}
}
}
My test case reads as follows:
#SuppressWarnings("static-access")
#Test
public void testDetermineMaximumScans() throws ParseException{
PowerMock.mockStatic(Calendar.class);
String beginningTime = "18:00";
String endingTime = "05:00";
mockAfterHoursBegin = parser.parse(beginningTime);
mockAfterHoursEnd = parser.parse(endingTime);
mockCurrentTime = parser.parse(parser.format(new Date()));
EasyMock.expect(Calendar.getInstance()).andReturn(mockCalendar);
EasyMock.expect(mockCalendar.get(Calendar.DAY_OF_WEEK)).andReturn(6);
EasyMock.replay(mocks);
offHourMaximumCalculator.determineDefaultMaximumScans();
EasyMock.verify(mocks);
}
As of now, all of my attempts to return a specific value result in the following assertion error. Now I vaguely understand why it's returning the default but I do not see why I can't force the value or how to get around this expectation. Mocks in general are still a frustrating mystery to me. What am I missing?
java.lang.AssertionError:
Expectation failure on verify:
Calendar.get(7): expected: 1, actual: 0
Mocks are fairly simple. But wanting to mock static methods is a big running after complexity. I generally do not recommend to mock something like a Calendar. If you do weird and complex thing with it, just encapsulate in something you can test and mock easily.
And in fact, we pretty much never use Calendar.getInstance(). It returns something according to the locale. But it's rare that you don't want a specific calendar i.e. GregorianCalendar. So just do new GregorianCalendar.
But anyway, add a protected method doing
protected Calendar newCalendar() {
return Calendar.getInstance(); // or new GregorianCalendar()
}
will take 2 minutes and then a simple partial mock will do the trick.
Finally, I also don't recommend to use Calendar. You have a much nicer API in java.util.date in Java 8.
All this said, here is how you should do it. Calendar is a system class, so you need to follow a real specific path which is explained here.
#RunWith(PowerMockRunner.class)
#PrepareForTest(Calendar.class)
public class MyTest {
#Test
public void testDetermineMaximumScans() throws ParseException {
PowerMock.mockStatic(Calendar.class);
Calendar calendar = mock(Calendar.class);
EasyMock.expect(Calendar.getInstance()).andReturn(calendar);
EasyMock.expect(calendar.get(Calendar.DAY_OF_WEEK)).andReturn(6);
// really important to replayAll to replay the static expectation
PowerMock.replayAll(calendar);
assertThat(Calendar.getInstance().get(Calendar.DAY_OF_WEEK)).isEqualTo(6);
// and verifyAll is you want to verify that the static call actually happened
PowerMock.verifyAll();
}
}
When I execute the following test, the original object is being returned and not the mock, so the real method getLevelCriteriaForLevel(level) is being executed (I observed that with the debugger). Why is that so? I'm pretty sure that this already worked yesterday and I didn't change anything there.
I already tried
#PrepareForTest({LevelCriteria.class, LevelGenerator.class})
or used the MockitoJunitRunner as I did before, but this doesn't help either.
Here is the code (generateConcreteLevel is a private method. The expected exception is only thrown when I pass this data from the mock. Otherwise it's not thrown. The test fails because the exception is not thrown, because the test doesn't use the mock object but the real object):
public class LevelGenerator
{
public void createLevel(int level)
{
generateConcreteLevel(levelCriteria.getLevelCriteriaForLevel(level));
}
private void generateConcreteLevel(LevelCriterion levelCriterion)
{
int entryGroupCount = levelCriterion.getEntryGroupCount();
int exitGroupCount = levelCriterion.getExitGroupCount();
int exitsWhileEntries = levelCriterion.getExitsWhileEntries();
int maxGroupSize = levelCriterion.getMaxGroupSize();
List<Question> questions = levelCriterion.getQuestions();
int speed = levelCriterion.getSpeed();
Range blueItemsCount = levelCriterion.getBlueItemsCount();
Range brownItemsCount = levelCriterion.getBrownItemsCount();
Range greenItemsCount = levelCriterion.getGreenItemsCount();
Range redItemsCount = levelCriterion.getRedItemsCount();
Range whiteItemsCount = levelCriterion.getWhiteItemsCount();
Range timespanBetweenGroups = levelCriterion.getTimespanBetweenGroups();
float fractionOfCarAmountToLeave = levelCriterion.getFractionOfCarAmountToLeave();
float fractionOfMinimumItemsAmountInCarParkToStartExits = levelCriterion.getFractionOfMinimumItemsAmountInCarParkToStartExits();
checkItemsFitInEntryGroups(entryGroupCount, maxGroupSize, blueItemsCount, brownItemsCount, greenItemsCount, redItemsCount, whiteItemsCount);
}
private void checkItemsFitInEntryGroups(int entryGroupCount, int maxGroupSize, Range... ranges)
{
int totalRangeCount = 0;
for (Range range : ranges)
{
totalRangeCount += range.getMaximum();
}
if (totalRangeCount > entryGroupCount * maxGroupSize)
{
throw new UnsupportedOperationException("Error in level criterion: Not enough entry groups for Items.");
}
}
}
and the test...
#RunWith(PowerMockRunner.class)
public class LevelGeneratorTest
{
#Mock
private LevelCriteria levelCriteriaMock;
#InjectMocks
private LevelGenerator levelGenerator;
#Test(expected=UnsupportedOperationException.class)
public void tooLessPositionsInEntryGroups()
{
LevelCriterion levelCriterion = new LevelCriterion.LevelCriterionBuilder()
.withBlueItemsCount(new Range(10, 10))
.withEntryGroupCount(3)
.withExitGroupCount(3)
.withMaxGroupSize(3)
.build();
when(levelCriteriaMock.getLevelCriteriaForLevel(anyInt())).thenReturn(levelCriterion);
levelGenerator.createLevel(0);
}
}
By the way: It's not an Eclipse problem, since a Maven build produces the same error.
I know that I can execute the private method with PowerMockito's Whitebox directly what I will do after refactoring, but the question is, why when...then is not working here.
Assuming your question is:
Why is the real method getLevelCriteriaForLevel(level) executed when I expect to have the mocked implementation?
I will try to demonstrate that everything works as expected fine if you reproduce it is a simple example (switch from your current workspace if you need to).
I do not have you LevelCriterion.LevelCriterionBuilder() so I simplified your test by just instantiating a LevelCriterion (empty object). This is not relevant because in my implementation I will always return an UnsupportedOperationException.
Here is how my LevelGenerator looks like. The UnsupportedOperationException is as simple as possible LevelGenerator#generateConcreteLevel(LevelCriterion).
If implemented like this:
public class LevelGenerator
{
LevelCriteria levelCriteria;
public void createLevel(int level)
{
generateConcreteLevel(levelCriteria.getLevelCriteriaForLevel(level));
}
private void generateConcreteLevel(LevelCriterion levelCriteriaForLevel)
{
throw new UnsupportedOperationException("xxx");
}
}
The test is green, using a #RunWith(MockitoJUnitRunner.class) on top of LevelGeneratorTest.
I did not used #PrepareForTest or PowerMockRunner. I have Mockito version 1.9.5.
I am sure that I have not used the real getLevelCriteriaForLevel(level) implementation, because it looks like this:
public class LevelCriteria {
public LevelCriterion getLevelCriteriaForLevel(int level) {
throw new IllegalStateException("Unexpected call");
}
}
If the real getLevelCriteriaForLevel(int) is excuted the test is red (because an IllegalStateException is thrown).
And the test is still green...
This works with pure-Mockito (version 1.9.5) approach.
You should remove all other mocking library (PowerMock, EasyMock...)
Are you sure that your static call of when(..).thenReturn(..) is the Mockito one?
Have you tried: Mockito.when(..).thenReturn(..)
I hope it helps.
PS: I have seen that you updated the question. It is a little bit unfair for me, but I am not going to update my answer once again.
I do not need the implementation detail of generateConcreteLevel(..) to illustrate that the when(..) call is working. Read my answer again. Try it in a separate workspace and you will see by yourself.
PS-2: I am using Eclipse too... Why should it be a problem? Eclipse is a great IDE.
I figured out what's wrong. Unfortunately you don't see the real problem in this question since I simplified the classes:
My real implementation of LevelGenerator got a parameterized constructor today. That's the reason why it worked yesterday but not anymore. Obviously there are mock injection problems with Mockito when not using a standard constructor.
Result: The when...then works as excpected.
All,
I am currently using JUnit 4 for writing test cases. I am fairly new to JUnit and finding it difficult to test my main class which takes arguments. I have specified the arguments to my JUnit test class by:
1 > Right click JUnit test class
2 > Goto Run As -> Run Configurations
3 > Select the Arguments tab and specify a value (I have entered an invalid argument i.e. the main class expects the command line argument to be converted to an int and I am passing a String value that cannot be converted to int)
However, the main class that I am testing, if the command line argument cannot be converted to a int, than I throw IllegalArgumentException. However, the JUnit does not show the testMain() method as Error or Failure. I don't think my setup is right for the JUnit class. Can anyone please guide me where I am going wrong
To test your class main method simply write something like:
#Test(expected = IllegalArgumentException.class)
public void testMainWithBadCommandLine()
{
YourClass.main(new String[] { "NaN" });
}
Change the main() method to something like this:
public static void main(String[] args)
{
MyClass myclass = new MyClass(args);
myclass.go();
}
Move the code that was in main() to the new method go(). Now, your test method can do this:
public void myClassTest()
{
String[] args = new String[]{"one", "two"}; //for example
MyClass classUnderTest = new MyClass(testArgs);
classUnderTest.go();
}
Firstly the arguments should be in the program arguments section. Normally the launching point of the application that's the main method doesn't need to be tested if you design the app to be testable.
Refactor the class
public static class ArgumentValidator
{
public static boolean nullOrEmpty(String [] args)
{
if(args == null || args.length == 0)
{
throw new IllegalArgumentException(msg);
}
//other methods like numeric validations
}
}
You can now easily test the nullOrEmpty method using junit like
#Test(expected = IllegalArgumentException.class)
public void testBadArgs()
{
ArgumentValidator.nullOrEmpty(null);
}
I think this is a better approach