how to unit test code that should cause compile error - java

I have a class that take a ArrayList as parameter:
public class Foo {
private ArrayList<Bar> bars;
public Foo(ArrayList barList) {
bars = barList;
}
}
there is a bug that I can pass any ArrayList into the constructor:
// should compile error with this line
Foo foo = new Foo(new ArrayList<String>());
the problem is if I add this case to test suite, when the bug fixed, I can not compile it.
is there anyway to test this case?

I don't know of any language/unit test framework that will let you "test" for code that should not compile. If you can't compile it, there is nothing to test. You can however turn on all compiler warnings when building. I'm pretty sure passing an unparameterized collection is a big warning in any JVM after JDK5.

I feel it is bad practise and I don't really see a use for it, but see this example for how to test for compilations errors:
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
#RunWith(JUnit4.class)
public class CompileTest {
//A very naive way checking for any error
#Test(expected=java.lang.Error.class)
public void testForError() throws Exception {
this.is.not.a.statement;
}
//An example which check that we only find errors for regarding compilation errors.
#Test
public void expectNotCompilableMethod() {
try {
uncompilableMethod();
fail("No compile error detected");
} catch (Error e) {
assertTrue("Check for compile error message", e.getMessage().startsWith("Unresolved compilation problems"));
}
}
private void uncompilableMethod() {
do.bad.things;
}
}
Edit:
1) I am not sure how this may behave together with build-tools like maven. As far as I know maven breaks the build at compile-errors, so probably the tests will not even be executed.

Fix your method signature:
public Foo(ArrayList<Bar> barList) {
bars = barList;
}
Problem solved. (You probably also want to check for null.)

Related

instantiate object from derived class with constructor that takes super argument

Maybe what I am trying to do is not worthwhile, it sure feels that way after spending many days on it.
I have A Base Class shown here:
package jimmy.kilmer.com;
import java.awt.Color;
import jarPackageImports.AI;
import jarPackageImports.MovementAction;
import jarPackageImports.Info;
import jarPackageImports.PlayerAction;
public class GameAI extends AI {
public gameAI(Info info) {
super(info);
setJerseyNumber(32);
}
public Color getColor() {
return Color.RED;
}
public String getName() {
return "Usain Bolt";
}
public PlayerAction update() {
// TODO game movement actions
// all available methods not listed here...
info.getVelocity();
info.getX();
info.getY();
MovementAction steeringBehavior = null;
return steeringBehavior;
}
//basically used for testing setup
public int[][] populateAllPossibleNodes() {
int[][] allPossibleNodes = new int[screenWidth/20][screenHeight/20];
return allPossibleNodes;
}
}
I have been given a jar, that sets up the game environment. It uses reflection for the setup. I am not familiar with reflection, unfortunately, as I am more beginner level.
I have read a lot about TDD, and am convinced that can help me stay orderly, and code in a disciplined way. I have some say that TDD is not really useful for Game development, which the arguments may be true, in regard to making an "enjoyable game." But, from a purely coding standpoint, I remain steadfast in my believe that TDD is the way to go. But, that remains to be seen, since it is still theoretical. I would like to try it.
I have installed Junit 5, and have done many tutorials, but it's all pretty basic examples. My particular test case uses reflection, super classes, derived classes, dynamic data. My head is spinning.
My goal is just to get setup such that I can start doing some Test driven development.
Here is my Junit test class:
package jimmy.kilmer.com;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import jarPackageImports.Info;
class GameAITest {
private GameAITest AIObject;
private jarPackageImports.Info info;
#BeforeEach
void setUp() throws Exception {
AIObject = new GameAITest(info);
#AfterEach
void tearDown() throws Exception {
}
#Test
void testPopulateAllPossibleNodes() {
// 1. given/arrange
int[][] array1 = new int[80][65];
// 2. when/act
int[][] array2 = AIObject.populateAllPossibleNodes();
// 3. then/assert
assertArrayEquals(array1, array2);
}
}
That is my best stab so far, but it still get a compile error. Specifically:
java.lang.NullPointerException:Cannot invoke "jarPackageImports.Info.getScene()" because "this.info" is null
In summation:
maybe everything I am trying is rubbish?
Do I need to use dynamic junit testing? I would have to read up on that.
Do I need to mock (use Mockito?) to instantiate an object to test? I would need to read up on that as well.
Is it possible to instantiate an object from GameAI? Do I need to/how would I use relection to do that? class.getConstructors()? And, I would have to read up on that.
thanks in advance.

JUnit5 - How to get test result in AfterTestExecutionCallback

I write JUnit5 Extension. But I cannot find way how to obtain test result.
Extension looks like this:
import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
import org.junit.jupiter.api.extension.TestExtensionContext;
public class TestResultExtension implements AfterTestExecutionCallback {
#Override
public void afterTestExecution(TestExtensionContext context) throws Exception {
//How to get test result? SUCCESS/FAILED
}
}
Any hints how to obtain test result?
This work for me:
public class RunnerExtension implements AfterTestExecutionCallback {
#Override
public void afterTestExecution(ExtensionContext context) throws Exception {
Boolean testResult = context.getExecutionException().isPresent();
System.out.println(testResult); //false - SUCCESS, true - FAILED
}
}
#ExtendWith(RunnerExtension.class)
public abstract class Tests {
}
As other answers point out, JUnit communicates failed tests with exceptions, so an AfterTestExecutionCallback can be used to gleam what happened. Note that this is error prone as extension running later might still fail the test.
Another way to do that is to register a custom TestExecutionListener. Both of these approaches are a little roundabout, though. There is an issue that tracks a specific extension point for reacting to test results, which would likely be the most straight-forward answer to your question. If you can provide a specific use case, it would be great if you could head over to #542 and leave a comment describing it.
You can use SummaryGeneratingListener from org.junit.platform.launcher.listeners
It contains MutableTestExecutionSummary field, which implements TestExecutionSummary interface, and this way you can obtain info about containers, tests, time, failures etc.
You can create custom listener, for example:
Create class that extends SummaryGeneratingListener
public class ResultAnalyzer extends SummaryGeneratingListener {
#Override
public void testPlanExecutionFinished(TestPlan testPlan) {
//This method is invoked after all tests in all containers is finished
super.testPlanExecutionFinished(testPlan);
analyzeResult();
}
private void analyzeResult() {
var summary = getSummary();
var failures = summary.getFailures();
//Do something
}
}
Register listener by creating file
src\main\resources\META-INF\services\org.junit.platform.launcher.TestExecutionListener
and specify your implementation in it
path.to.class.ResultAnalyzer
Enable auto-detection of extensions, set parameter
-Djunit.jupiter.extensions.autodetection.enabled=true
And that's it!
Docs
https://junit.org/junit5/docs/5.0.0/api/org/junit/platform/launcher/listeners/SummaryGeneratingListener.html
https://junit.org/junit5/docs/5.0.0/api/org/junit/platform/launcher/listeners/TestExecutionSummary.html
https://junit.org/junit5/docs/current/user-guide/#extensions-registration-automatic
I have only this solution:
String testResult = context.getTestException().isPresent() ? "FAILED" : "OK";
It seems that it works well. But I am not sure if it will work correctly in all situations.
Fails in JUnit are propagated with exceptions. There are several exceptions, which indicate various types of errors.
So an exception in TestExtensionContext#getTestException() indicates an error. The method can't manipulate actual test results, so depending on your use case you might want to implement TestExecutionExceptionHandler, which allows you to swallow exceptions, thus changing whether a test succeeded or not.
You're almost there.
To implement a test execution callback and get the test result for logging (or generating a report) you can do the following:
import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
public class TestResultExtension implements AfterTestExecutionCallback
{
#Override
public void afterTestExecution(ExtensionContext context) throws Exception
{
// check the context for an exception
Boolean passed = context.getExecutionException().isEmpty();
// if there isn't, the test passed
String result = passed ? "PASSED" : "FAILED";
// now that you have the result, you can do whatever you want
System.out.println("Test Result: " + context.getDisplayName() + " " + result);
}
}
And then you just add the TestResultExtension using the #ExtendWith() annotation for your test cases:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import static org.junit.jupiter.api.Assertions.assertTrue;
#ExtendWith(TestResultExtension.class)
public class SanityTest
{
#Test
public void testSanity()
{
assertTrue(true);
}
#Test
public void testInsanity()
{
assertTrue(false);
}
}
It's a good idea to extend a base test that includes the extension
import org.junit.jupiter.api.extension.ExtendWith;
#ExtendWith(TestResultExtension.class)
public class BaseTest
{}
And then you don't need to include the annotation in every test:
public class SanityTest extends BaseTest
{ //... }

NoClassDefFoundError when mock an interface using JNI

I'm investigating the reason why the following scenario causes NoClassDefFoundError, which involves the use of jmockit and JNI.
Here's the classes:
MyJNI.class
class MyJNI {
MyJNI() {}
public static final native int getInt();
}
MyTestInterface.class
public interface MyTestInterface {
int INT_FROM_JNI = MyJNI.getInt();
}
MyTestImp.class
public class MyTestImp implements MyTestInterface {
public MyTestImp() {}
}
DummyTest.java
#RunWith(JMockit.class)
public class DummyTest {
#Mocked
MyTestInterface myTest;
#Test
public void dummy() { assertTrue(true); }
}
FailingTest.java
#RunWith(JMockit.class)
public class FailingTest {
#Mocked
MyTestImp myTest;
#Test
public void shouldPass() { assertTrue(true); }
}
If we run DummyTest.java and FailingTest.java in sequence (the order matters), the test in FailingTest.java fails with the error message "java.lang.NoClassDefFoundError: xxx.xxx.xxx.MyTestInterface".
Specifically, any of the following change corrects the error:
(a) running the tests in reverse order: FailingTest.java and then DummyTest.java
(b) in "DummyTest.java", change "MyTestInterface myTest;" to "MyTestImp myTest;"
(c) in "MyTestInterface.class", change "int INT_FROM_JNI = MyJNI.getInt();" to "int INT_FROM_JNI = 1;".
(d) in "FailingTest.java", change "MyTestImp myTest;" to "MyTestInterface myTest;"
I couldn't find a good explanation to this. In this case the unit tests are not independent anymore. It looks like in the scenario mock MyTestInterface would cause problem in the other test files when trying to use MyJNI, and in this case would make MyTestInterface not found in runtime.
Anyone has any clues of how to explain this? Thanks!

JUnit #Theory : is there a way to throw meaningful exception?

I tried Junit #Theory test style recently : it's a really efficient way of testing. However, i not pleased with the exception that are thrown when a test fails. Example :
import static org.junit.Assert.assertEquals;
import org.junit.experimental.theories.DataPoint;
import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;
#RunWith(Theories.class)
public class TheoryAndExceptionTest {
#DataPoint
public static String yesDataPoint = "yes";
#Theory
public void sayNo(final String say) {
assertEquals("no",say);
}
}
I expect this test to throw a descriptive exception, but instead of getting something like :
org.junit.ComparisonFailure: expected:<'[no]'> but was:<'[yes]'>
... I get this :
org.junit.experimental.theories.internal.ParameterizedAssertionError: sayNo(yes) at
....
[23 lines of useless stack trace cut]
...
Caused by: org.junit.ComparisonFailure: expected:<'[no]'> but was:<'[yes]'>
....
Is there a way to get rid of the 24 first lines that tell nothing about *my*test, except that yesDataPoint #DataPoint causes the failure ? That's an information i need, to know what is failing, but i really would like to know how it fails on the same time.
[edited]
I replaced org.fest.assertions usage by classic org.junit.Assert.assertEquals, to avoid confusion.
Additionally, it's not related either with Eclipse : that long (useless/confusing) stack trace is what you get too when you run and fail a #Theory from the command line.
Is there a problem with catching the ComparisonFailure and printing the GetMessage() of it?
public void sayNo(final String say) {
try {
assertThat(say).isEqualTo("no");
}catch(ComparisonFailure e) {
System.out.println(e.getMessage);
}
}
Apologies if there is something I misunderstand.
Edit: ComparisonFailure also has getExpected() and getActual() methods that you can invoke if you are looking for certain formatting.
You have a very strange library. You have a strange syntax for assertThat. I would propose:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.experimental.theories.*;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
#RunWith(Theories.class)
public class TheoryAndExceptionTest {
#DataPoint
public static String yesDataPoint = "yes";
#Theory
public void sayNo(final String say) {
assertThat(say,is("no"));
}
#Test
public void yesNo() {
assertEquals("must be equal, ", "yes","no");
}
}
Then you'll have:
org.junit.experimental.theories.internal.ParameterizedAssertionError: sayNo(yesDataPoint)
....
Caused by: java.lang.AssertionError:
Expected: is "no"
got: "yes"
As for assertEqual you are right, it seems it won't help in Theories.
Only for the #Test:
org.junit.ComparisonFailure: must be equal, expected:<[yes]> but was:<[no]>
An addition:
You can also use
assertThat("must be equal, ", say,is("no"));
Than you'll have the output:
Caused by: java.lang.AssertionError: must be equal,
Expected: is "no"
got: "yes"
As for filtering extra lines, use Failure Trace View in Eclipse.

Adding Custom Messages to JUnit4 Style Exception Tests

I have the following test:
#Test(expected=ArithmeticException.class)
public void divideByZero() {
int n = 2 / 1;
}
as seen here.
I would like to add a message that will print if this test fails.
For instance if I was doing an Assertion test, I would do the following to add a message:
#Test public void assertFail(){
Assert.fail("This is the error message I want printed.");
Assert.assertEquals(true, false);
}
The second example should print out "This is the error message I want printed.". How do I set the first example message text?
Maybe #Rule annotation should help. Into your unit test class add sth like this:
import org.junit.Rule;
import org.junit.rules.MethodRule;
import org.junit.runners.model.Statement;
import org.junit.runners.model.FrameworkMethod;
import org.junit.internal.runners.model.MultipleFailureException;
...
#Rule
public MethodRule failureHandler = new MethodRule()
{
#Override
public Statement apply(final Statement base, FrameworkMethod method, Object target)
{
return new Statement()
{
#Override
public void evaluate() throws Throwable
{
List<Throwable> listErrors = new ArrayList<Throwable>();
try
{
// Let's execute whatever test runner likes to do
base.evaluate();
}
catch (Throwable testException)
{
// Your test has failed. Store the test case exception
listErrors.add(testException);
// Now do whatever you need, like adding your message,
// capture a screenshot, etc.,
// but make sure no exception gets out of there -
// catch it and add to listErrors
}
if (listErrors.isEmpty())
{
return;
}
if (listErrors.size() == 1)
{
throw listErrors.get(0);
}
throw new MultipleFailureException(listErrors);
}
};
}
};
Instead of collecting all the exceptions in listErrors you may consider wrapping testException with your exception with additional message and just throwing it.
I recommend instead naming the test to make it obvious what the test is testing, so when some of your tests fail, they tell you what the problem is. Here's an example using the ExpectedException rule:
#RunWith(JUnit4.class)
public class CalculatorTest {
#Rule
public ExpectedException exception = ExpectedException.none();
#Test
public void divisionByZeroShouldThrowArithmeticException() {
Calculator calculator = new Calculator();
exception.expect(ArithmeticException.class);
calculator.divide(10, 0);
}
}
For details on ExpectedException, see this article and the ExpectedException JavaDoc
If you are willing to use catch-exception instead of JUnit's built-in exception handling mechanisms, then your problem can be easily solved:
catchException(myObj).doSomethingExceptional();
assertTrue("This is the error message I want printed.",
caughtException() instanceof ArithmeticException);
I don't think you can easily, but this guy seems to have partially worked his way around it.

Categories