I starting to use FEST to help me to perform unit test on my Java Swing GUI.
For now, I managed to get through the documentation (mostly deprecated) and help me by looking at the Javadoc and the code.
Right now I am stuck on a problem while using the NoExitSecurityManager. The documentation is quite out dated but we can understand the big lines of it.
I simply try to test if my "Quit" MenuItem is working well in my GUI. So, I need to block the System.exit(0) and map the exit status of the program to a JUnit test.
Here is a simplified code I use to perform the test (the tested class is GraphicalUserInterface).
import org.junit.Test;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.fest.swing.annotation.RunsInEDT;
import org.fest.swing.edt.GuiQuery;
import org.fest.swing.edt.GuiActionRunner;
import org.fest.swing.fixture.FrameFixture;
import org.fest.swing.junit.testcase.FestSwingJUnitTestCase;
import org.fest.swing.security.NoExitSecurityManagerInstaller;
public class GraphicalUserInterfaceTest extends FestSwingJUnitTestCase {
private static FrameFixture gui;
private static NoExitSecurityManagerInstaller noExitSecurityManagerInstaller;
#BeforeClass
public static void setUpBeforeClass() throws Exception {
NoExitSecurityManagerInstaller.installNoExitSecurityManager(new ExpectExitSuccess());
}
#AfterClass
public static void tearDownAfterClass() throws Exception {
noExitSecurityManagerInstaller.uninstall();
}
#Override
protected void onSetUp() {
gui = new FrameFixture(robot(), createNewGUI());
gui.show();
}
#RunsInEDT
private GraphicalUserInterface createNewGUI() {
return GuiActionRunner.execute(new GuiQuery<GraphicalUserInterface>() {
protected GraphicalUserInterface executeInEDT() {
return new GraphicalUserInterface();
}
});
}
#Test
public final void testFileMenuQuitMenuItem() {
gui.menuItemWithPath("File", "Quit").click();
}
}
The ExitCallHook are coded like this (you can guess the other one easily).
import static org.junit.Assert.assertTrue;
import org.fest.swing.security.ExitCallHook;
public final class ExpectExitSuccess implements ExitCallHook {
#Override
public void exitCalled(int status) {
assertTrue(status == 0);
}
}
All the tests are performed well and everything seems to be ok except that I get a java.lang.NullPointerException at the end.
So, I wonder what did I do wrong (or what can I improve to not get this nullpointer exception at the end of the test).
I found the solution in the code. In fact, the proper way to do it is the following:
#Test
public final void testFileMenuQuitMenuItem() {
NoExitSecurityManagerInstaller noExitSecurityManagerInstaller =
NoExitSecurityManagerInstaller.installNoExitSecurityManager(new ExpectExitSuccess());
gui.menuItemWithPath("File", "Quit").click();
noExitSecurityManagerInstaller.uninstall();
}
This way prevent to pollute each test with a NoExitSecurityManager.
Related
I'm trying to learning Serenity BDD framework but i encounter some issues which need guidance from expect.I have downloaded serenity-cucumber4-starter-master from github.
Problems:
AFAIK, there is Tasks, Screen and Actions classes creation but I did not found it in the project according to this theory.
How is the implementation of this example different from screenplay design patterns?
My Code so far:
public class LoginTask implements Task {
private HomepageScreen hp;
#Override
#Step("Landing on Guru Bank Website")
public <T extends Actor> void performAs(T obj) {
obj.attemptsTo(Open.browserOn(hp));
}
}
#RunWith(SerenityRunner.class)
public class CucumberTestSuite {
#Managed(driver = "chrome")
private WebDriver browser;
private Actor john = Actor.named("john");
// =================================================================================
#Before
public void setup() {
john.can(BrowseTheWeb.with(browser));
}
#Test
public void login() throws InterruptedException {
//givenThat(john).can(BrowseTheWeb.with(browser));
System.out.println("Automate web browser");
//givenThat(john).wasAbleTo(LoginTask.);
Thread.sleep(9000);
}
}
givenThat() method is undefined. Where to get the import location?
Please help. Thanks.
The givenThat() method (and other similar methods) are defined in net.serenitybdd.screenplay.GivenWhenThen.
import static net.serenitybdd.screenplay.GivenWhenThen.seeThat;
I've tried to modify minecraft by adding a new item called "uranium". Therefore I created the class "Trauma.java" in the main package and a few other classes listed below.
All packages and classes:
Package Explorer
Trauma.java
package main;
import items.ItemUranium;
import net.minecraft.item.Item;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.registry.GameRegistry;
import proxy.ServerProxy;
#Mod(modid = Trauma.MODID)
public class Trauma {
public static final String MODID = "Trauma";
#SidedProxy(clientSide = "proxy.ClientProxy", serverSide = "proxy.ServerProxy")
public static ServerProxy proxy;
public static ItemUranium uranium = new ItemUranium();
#EventHandler
public void preInit(FMLPreInitializationEvent event) {
GameRegistry.register(uranium);
}
#EventHandler
public void init(FMLInitializationEvent event) {
proxy.registerClientStuff();
}
#EventHandler
public void postInit(FMLPostInitializationEvent event) {
}
}
BasicItem.java
package items;
import net.minecraft.item.Item;
public class BasicItem extends Item {
public BasicItem(String name) {
setUnlocalizedName(name);
setRegistryName(name);
}
}
ItemUranium.java
package items;
public class ItemUranium extends BasicItem {
public ItemUranium() {
super("uranium");
}
}
ClientProxy.java
package proxy;
import items.BasicItem;
import main.Trauma;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
public class ClientProxy extends ServerProxy {
#Override
public void registerClientStuff () {
registerItemModel(Trauma.uranium);
}
public static void registerItemModel(BasicItem item) {
Minecraft.getMinecraft().getRenderItem().getItemModelMesher().register(item, 0, new ModelResourceLocation(Trauma.MODID + ":" + item.getRegistryName(), "inventory"));
}
}
ServerProxy.java
package proxy;
public class ServerProxy {
public void registerClientStuff() {}
}
uranium.json
{
"parent": "item/generated",
"textures": {
"layer0": "Trauma:items/uranium"
}
}
uranium.png
ingame
Also I don't know why the item in inventory isn't called uranium...
I spent two hours on fixing the problem and it didn't help so it would be really nice if somebody of you may help me.
Thanks :)
Don't use the Model Mesher:
The model mesher is Vanilla (Mojang) code and using it correctly has always been finicky and unreliable, failing if you called it too early and failing if you called it too late. So Forge added the ModelLoader class to resolve that problem.
Replace this line:
Minecraft.getMinecraft().getRenderItem().getItemModelMesher().register(...)
With this line:
ModelLoader.setCustomModelResourceLocation(...)
The ... contents are identical.
Second, depending on what version of Minecraft you're using, you should...:
Stop using GameRegistry.Register
Instead use the RegistryEvent.Register<T> events (where <T> will be <Block> to register blocks, <Item> to register items, etc)
Register your models in the ModelRegistryEvent and no where else.
This event is #SideOnly(CLIENT) and can be subscribed to in your client proxy, avoiding the need to forward references through your proxy class. Eg. I do it like this, where lines 197-199 is the most common scenario needed, where the array is populated during the item registration event. The rest of that method handles the custom state mappers and custom mesh definitions that are used by only a handful of items/blocks and not relevant here.
Include your Mod ID in your unlocalized name. The best way to do this would be setUnlocalizedName(getRegistryName().toString());
See also the Forge documentation on events.
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
{ //... }
Using EasyMock 3.2. In order to unit test an UI, I have to mock some dependencies. One of them is Page. Base class for UI tests looks like this:
abstract class AbstractUiTest {
#Before
public function setUpUiDependencies() {
Page page = createNiceMock(Page.class);
Ui.setCurrentPage(page);
}
}
Most of the time I don't use the page explicity, it's just there not to throw NullPointerException when e.g. Ui calls getPage().setTitle("sth") etc.
However, in a few tests I want to explicity check if something has happend with the page, e.g.:
public class SomeTest extends AbstractUiTest {
#Test
public void testNotification() {
// do something with UI that should cause notification
assertNotificationHasBeenShown();
}
private void assertNotificationHasBeenShown() {
Page page = Ui.getCurrentPage(); // this is my nice mock
// HERE: verify somehow, that page.showNotification() has been called
}
}
How to implement the assertion method? I would really want to implement it without recording behavior to the page, replaying and verifying it. My problem is a bit more complicated, but you should get the point.
EDIT: I think that perhaps this is not really needed, since simply using replay and verify should check that the expected methods were actually called. But you said you want to do this without replaying and verifying. Can you explain why you have that requirement?
I think that you can use andAnswer and an IAnswer. You don't mention what the return value of page.showNotification() is. Assuming it returns a String, you could do this:
import static org.easymock.EasyMock.expect;
import static org.junit.Assert.assertTrue;
import java.util.concurrent.atomic.AtomicBoolean;
import org.easymock.IAnswer;
import org.junit.Ignore;
import org.junit.Test;
public class SomeTest extends AbstractUiTest {
#Test
public void shouldCallShowNotification() {
final AtomicBoolean showNotificationCalled = new AtomicBoolean();
expect(page.showNotification()).andAnswer(new IAnswer<String>() {
#Override
public String answer() {
showNotificationCalled.set(true);
return "";
}
});
replay(page);
Ui.getCurrentPage();
verify(page);
assertTrue("showNotification not called", showNotificationCalled.get());
}
}
If showNotification returns void, I believe you would need to do this:
import static org.easymock.EasyMock.expectLastCall;
import static org.junit.Assert.assertTrue;
import java.util.concurrent.atomic.AtomicBoolean;
import org.easymock.IAnswer;
import org.junit.Ignore;
import org.junit.Test;
public class SomeTest extends AbstractUiTest {
#Test
public void shouldCallShowNotification() {
final AtomicBoolean showNotificationCalled = new AtomicBoolean();
page.showNotification();
expectLastCall().andAnswer(new IAnswer<Void>() {
#Override
public Void answer() {
showNotificationCalled.set(true);
return null;
}
});
replay(page);
Ui.getCurrentPage();
verify(page);
assertTrue("showNotification not called", showNotificationCalled.get());
}
}
Note: I've used an AtomicBoolean to record whether the method was called. You could also use a boolean array of a single element, or your own mutable object. I used AtomicBoolean not for its concurrency properties, but simply because it is a handy mutable boolean object that is already present in the Java standard libraries.
The other thing that I have done to verify that a method was being called is to not use a mock at all, but to create an instance of Page as an anonymous inner class and override the showNotification method, and record somewhere that the call occurred.
Use a nice mock in the tests where you don't care what happens to page and a normal mock in those tests where you want to test something explicit - and use expect, verify etc. I.e. have two variables in your setup method: nicePage (acts as a stub) and mockPage (acts as a mock)
We occasionally have bugs that appear once in every X runs. Before people check in stuff (where it is automatically JUnit'd), our devs need to pass JUnit locally via Eclipse.
Is there some convenient way (built in or high-quality Plugin) to make Eclipse run the same test X times and stop if there's a failure? An alternative to just clicking Run X times?
Note that I'm looking for something in the UI (e.g., right click and say "Run X times" instead of just "Run").
If the for loop works, then I agree with nos.
If you need to repeat the entire setup-test-teardown, then you can use a TestSuite:
Right-click on the package containing the test to repeat
Go to New and choose to create a JUnit test SUITE
Make sure that only the test you want to repeat is selected and click through to finish.
Edit the file to run it multiple times.
In the file you just find the
addTestSuite(YourTestClass.class)
line, and wrap that in a for loop.
I'm pretty sure that you can use addTest instead of addTestSuite to get it to only run one test from that class if you just want to repeat a single test method.
If you really want to run a test class until failure, you need your own runner.
#RunWith(RunUntilFailure.class)
public class YourClass {
// ....
}
which could be implemented as follows...
package com.example;
import org.junit.internal.runners.*;
import org.junit.runner.notification.*;
import org.junit.runner.*;
public class RunUntilFailure extends Runner {
private TestClassRunner runner;
public RunUntilFailure(Class<?> klass) throws InitializationError {
this.runner = new TestClassRunner(klass);
}
#Override
public Description getDescription() {
Description description = Description.createSuiteDescription("Run until failure");
description.addChild(runner.getDescription());
return description;
}
#Override
public void run(RunNotifier notifier) {
class L extends RunListener {
boolean fail = false;
public void testFailure(Failure failure) throws Exception { fail = true; }
}
L listener = new L();
notifier.addListener(listener);
while (!listener.fail) runner.run(notifier);
}
}
...releasing untested code, feeling TDD guilt :)
Based on #akuhn's answer, here is what I came up with - rather than running forever, this will run 50 times or until failure, whichever comes first.
package com.foo
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunListener;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;
public class RunManyTimesUntilFailure extends Runner {
private static final int MAX_RUN_COUNT = 50;
private BlockJUnit4ClassRunner runner;
#SuppressWarnings("unchecked")
public RunManyTimesUntilFailure(final Class testClass) throws InitializationError {
runner = new BlockJUnit4ClassRunner(testClass);
}
#Override
public Description getDescription() {
final Description description = Description.createSuiteDescription("Run many times until failure");
description.addChild(runner.getDescription());
return description;
}
#Override
public void run(final RunNotifier notifier) {
class L extends RunListener {
boolean shouldContinue = true;
int runCount = 0;
#Override
public void testFailure(#SuppressWarnings("unused") final Failure failure) throws Exception {
shouldContinue = false;
}
#Override
public void testFinished(#SuppressWarnings("unused") Description description) throws Exception {
runCount++;
shouldContinue = (shouldContinue && runCount < MAX_RUN_COUNT);
}
}
final L listener = new L();
notifier.addListener(listener);
while (listener.shouldContinue) {
runner.run(notifier);
}
}
}
I know it doesn't answer the question directly but if a test isn't passing every time it is run it is a test smell known as Erratic Test. There are several possible causes for this (from xUnit Test Patterns):
Interacting Tests
Interacting Test Suites
Lonely Test
Resource Leakage
Resource Optimism
Unrepeatable Test
Test Run War
Nondeterministic Test
The details of each of these is documented in Chapter 16 of xUnit Test Patterns.
Here is a post I wrote that shows several ways of running the tests repeatedly with code examples:
http://codehowtos.blogspot.com/2011/04/run-junit-test-repeatedly.html
You can use the #Parametrized runner, or use the special runner included in the post
There is also a reference to a #Retry implementation
I don't believe there's a built in way for junit to do exactly what you're asking for.
If multiple runs produce different result, you should have a unit test testing that case. Wich might be as simple as running a for loop in the relevant test cases.
It is possible to implement such an loop with TestRules (since JUnit 4.9)
A very simple implementation that runs every Test 10 times:
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
public class SimpleRepeatRule implements TestRule {
private static class SimpleRepeatStatement extends Statement {
private final Statement statement;
private SimpleRepeatStatement(Statement statement) {
this.statement = statement;
}
#Override
public void evaluate() throws Throwable {
for (int i = 0; i < 10; i++) {
statement.evaluate();
}
}
}
#Override
public Statement apply(Statement statement, Description description) {
return new SimpleRepeatStatement(statement);
}
}
usage:
public class Run10TimesTest {
#Rule
public SimpleRepeatRule repeatRule = new SimpleRepeatRule();
#Test
public void myTest(){...}
}
For a more useful implementation based on an annotation that define which test method has to been executed how often have a look at this blog:
http://www.codeaffine.com/2013/04/10/running-junit-tests-repeatedly-without-loops/