What is the equivalent of ExternalResource and TemporaryFolder in JUnit 5? - java

According to the JUnit 5 User Guide, JUnit Jupiter provides backwards compatibility for some JUnit 4 Rules in order to assist with migration.
As stated above, JUnit Jupiter does not and will not support JUnit 4 rules natively. The JUnit team realizes, however, that many organizations, especially large ones, are likely to have large JUnit 4 codebases including custom rules. To serve these organizations and enable a gradual migration path the JUnit team has decided to support a selection of JUnit 4 rules verbatim within JUnit Jupiter.
The guide goes on to say that one of the rules is ExternalResource, which is a parent for TemporaryFolder.
However, the guide unfortunately doesn't go on to say what the migration path is, or what the equivalent is for those writing new JUnit 5 tests. So what should we use?

Interesting article by author of TemporaryFolderExtension for JUnit5
and
his code repo on github
JUnit5.0.0 is now in general release so let's hope they turn their attention to making the experimental stuff production-ready.
Meanwhile, it seems the TemporaryFolder rule will still work with JUnit5 docs
use this:
#EnableRuleMigrationSupport
public class MyJUnit5Test {
and this:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-migrationsupport</artifactId>
<version>5.0.0</version>
</dependency>

As far as I understood, there can be no one to one mapping from ExternalResource to an equivalent in JUnit5. The concepts just don't fit. In JUnit4, the ExternalResource basically gives you a before and an after callback, but within the rule, you have no control about what before and after actually means. You could use it with #Rule or with #ClassRule.
In JUnit5, the extension is defined to hook in specific extension points and thus the 'when' is well defined.
Another difference in concepts would be, that you can have a state in JUnit4 rules, but your JUnit5 extensions shouldn't have any state. Instead, all state should go to the execution context.
Nevertheless, here is an option I came along with, where before and after relates to each test method:
public abstract class ExternalResourceExtension
implements BeforeTestExecutionCallback, AfterTestExecutionCallback {
#Override
public void beforeTestExecution(ExtensionContext context) throws Exception {
before(context);
}
#Override
public void afterTestExecution(ExtensionContext context) throws Exception {
after(context);
}
protected abstract void before(ExtensionContext context);
protected abstract void after(ExtensionContext context);
}

JUnit 5.4 comes with a built-in extension to handle temporary directories in tests.
#org.junit.jupiter.api.io.TempDir annotation can be used in order to annotate class field or a parameter in a lifecycle (e.g. #BeforeEach) or test method of type File or Path.
import org.junit.jupiter.api.io.TempDir;
#Test
void writesContentToFile(#TempDir Path tempDir) throws IOException {
// arrange
Path output = tempDir
.resolve("output.txt");
// act
fileWriter.writeTo(output.toString(), "test");
// assert
assertAll(
() -> assertTrue(Files.exists(output)),
() -> assertLinesMatch(List.of("test"), Files.readAllLines(output))
);
}
You can read more on this in my blog post, where you will find some more examples on utilizing this built-in extension: https://blog.codeleak.pl/2019/03/temporary-directories-in-junit-5-tests.html.

The documentation for that is still in the making - see pull request #660.

Temporary folders now have a solution in the way of #TempDir. However, what about the idea behind ExternalResources in general? Perhaps it's for a mock database, a mock HTTP connection, or some other custom resource you want to add support for?
The answer, it turns out is you can use the #RegisterExtension annotation to achieve something quite similar.
Example of use:
/**
* This is my resource shared across all tests
*/
#RegisterExtension
static final MyResourceExtension MY_RESOURCE = new MyResourceExtension();
/**
* This is my per test resource
*/
#RegisterExtension
final MyResourceExtension myResource = new MyResourceExtension();
#Test
void test() {
MY_RESOURCE.doStuff();
myResource.doStuff();
}
And here's the basic scaffolding of MyResourceExtension:
public class MyResourceExtension implements BeforeAllCallback, AfterAllCallback,
BeforeEachCallback, AfterEachCallback {
private SomeResource someResource;
private int referenceCount;
#Override
public void beforeAll(ExtensionContext context) throws Exception {
beforeEach(context);
}
#Override
public void afterAll(ExtensionContext context) throws Exception {
afterEach(context);
}
#Override
public void beforeEach(ExtensionContext context) throws Exception {
if (++referenceCount == 1) {
// Do stuff in preparation
this.someResource = ...;
}
}
#Override
public void afterEach(ExtensionContext context) throws Exception {
if (--referenceCount == 0) {
// Do stuff to clean up
this.someResource.close();
this.someResource = null;
}
}
public void doStuff() {
return this.someResource.fooBar();
}
}
You could of course wrap this all up as an abstract class and have MyResourceExtension implement just protected void before() and protected void after() or some such, if that's your thing, but I'm omitting that for brevity.

Related

How to have DropWizard JUnit App Rule definition use startup information from a docker rule?

The general problem I am trying to solve is this. I have a solution, but it's very clunky, and I'm hoping someone knows of a more orderly one.
Dropwizard offers a JUnit TestRule called DropwizardAppRule, which is used for integration tests. You use it like this:
#ClassRule
public static final DropWizardAppRule<MyConfiguration> APP_RULE = new DropwizardAppRule(MyApplication.class, myYmlResourceFilePath, ConfigOverride("mydatabase.url", myJdbcUrl));
It will start up your application, configuring it with your yml resource file, with overrides that you specified in the constructor. Note, however, that your overrides are bound at construction time.
There are also JUnit rules out there to start up a Docker container, and I'm using one to start up MySql, and a JUnit RuleChain to enforce the fact that the container must start up before I launch my Dropwizard application that depends on it.
All that works great, if I'm willing to specify in advance what port I want the MySql container to expose. I'm not. I want these integration tests to run on a build machine, quite possibly in parallel for branch builds of the same project, and I would strongly prefer to use the mechanism where you ask Docker to pick any available port, and use that.
The problem I run into with that, is that the exposed container port is not known at the time that the DropwizardAppRule is constructed, which is the only time you can bind configuration overrides.
The solution I adopted was to make a wrapper JUnit Rule, like so:
public class CreateWhenRunRuleWrapper<T extends ExternalResource> extends ExternalResource {
private final Supplier<T> wrappedRuleFactory;
private T wrappedRule;
public CreateWhenRunRuleWrapper(Supplier<T> wrappedRuleFactory) {
this.wrappedRuleFactory = wrappedRuleFactory;
}
public T getWrappedRule() {
return wrappedRule;
}
#Override
protected void before() throws Throwable {
wrappedRule = wrappedRuleFactory.get();
wrappedRule.before();
}
#Override
protected void after() {
wrappedRule.after();
}
}
This works, allowing me to construct the DropWizardAppRule class in the before() method, but is quite obviously outside JUnit's design intent, as shown by the fact that I had to locate it in the org.junit.rules package, in order to empower my class to be able to call the before() and after() methods of the late-created Rule.
What would be a more orderly, best practice way to accomplish the same objective?
2 Options we came up with:
The hacky solution is to use static {} which executes the code after spinning up the container but before initialising the dropwizard instance:
public static final GenericContainer mongodb = new GenericContainer("mongo:latest").withExposedPorts(27017);
static {
mongodb.start();
System.setProperty("dw.mongoConfig.uri", "mongodb://" + mongodb.getContainerIpAddress() + ":" + mongodb.getMappedPort(27017));
}
#ClassRule
public static final DropwizardIntegrationAppRule<Config> app1 = new DropwizardIntegrationAppRule<>(Service.class);
The second option is cleaner and much like yours.
private static final MongoDContainerRule mongo = new MongoDContainerRule();
private static final DropwizardIntegrationAppRule<Config> app = new DropwizardIntegrationAppRule<>(Service.class);
#ClassRule
public static final RuleChain chain = RuleChain
.outerRule(mongo)
.around(app)
MongoDContainerRule is like your wrapper but it also sets the right port through system properties.
public class MongoDContainerRule extends MongoDBContainerBase {
private static final GenericContainer mongodb = new GenericContainer("mongo:latest").withExposedPorts(27017);
#Override
protected void before() throws Throwable {
mongodb.start();
System.setProperty("dw.mongoConfig.uri", "mongodb://" + mongodb.getContainerIpAddress() + ":" + mongodb.getMappedPort(27017));
System.setProperty("dw.mongoConfig.tls", "false");
System.setProperty("dw.mongoConfig.dbName", DB_NAME);
}
#Override
protected void after() {
mongodb.stop();
}
}
The container will expose mongodb on a free port. mongodb.getMappedPort(internalPort) will return it. System.setProperty("dw.*") injects values into the dropwizard config.

Mocking a class object using Mockito and PowerMockito

Is it possible to mock a class object using Mockito and/or PowerMockito?
Something like:
Class<Runnable> mockRunnableClass = mock(Class<Runnable>.class);
An alternative to mocking Class might be to use a Factory instead. I know you are concerned about refactoring, but this could be done without changing the public API of the class. You haven't provided much code to understand the class you are trying to test, but here's an example of refactoring without changing the API. It's a trivial class, but it might give you an idea.
public class Instantiator {
public Runnable getNewInstance(Class<Runnable> runnableClass) throws Exception {
return runnableClass.newInstance();
}
}
Of course, the easiest thing to do to test this trivial class would be to use a genuine Runnable class, but if you tried to mock the Class, you would run into the problems you're having. So, you could refactor it thus:
public class PassThruFactory {
public Object newInstance(Class<?> clazz) throws Exception {
return clazz.newInstance();
}
}
public class Instantiator {
private PassThruFactory factory = new PassThruFactory();
public Runnable getNewInstance(Class<Runnable> runnableClass) throws Exception {
return (Runnable)factory.newInstance(runnableClass);
}
}
Now Instantiator does exactly the (trivially simple) thing it was doing before with the same public API and no need for any client of the class to do any special injecting of their own. However, if you wanted to mock the factory class and inject it, that's very easy to do.
why not using an agent if you can't refactor the code there isn't many options, as #jherics mentionned, java system classes are loaded by the bootstrap classloader and powermock can't redefine their bytecode.
However Powermock now coms with an agent, that will allow system classes mock. Check here for complete explanation.
The main idea is to modify your java command and add :
-javaagent: path/to/powermock-module-javaagent-1.4.12.jar
The basic thing this agent is doing is to definalize classes, to allow future mocking in a specific test, that's why you'll need to use specific types to communicate with the agent, for example with JUnit :
#Rule PowerMockRule rule = new PowerMockRule(); // found in the junit4 rule agent jar
TestNG is also supported. Just check the wiki page for more information.
Hope that helps.
First, as stated in the comments, you would need to do:
Class<Runnable> mockRunnableaClass = (Class<Runnable>)mock(Class.class);
But that won't work in the usual way because of a limitation with PowerMock. You cannot simply mock classes in from java.lang, java.net, java.io or other system classes because they're loaded by Java's bootstrap classloader and cannot be byte-code manipulated by PowerMock's classloader. (See PowerMock FAQ #4.) As of PowerMock 1.2.5, you can work around this. If the class you wanted to test was this:
public class ClassToTest {
private Class<Runnable> runnableClass;
public void setRunnableClass(Class<Runnable> runnableClass) {
this.runnableClass = runnableClass;
}
public Runnable foo() {
return runnableClass.newInstance();
}
}
Then you would do this:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ ClassToTest.class }) // Prepare the calling class for test
public class SystemClassUserTest {
#Test
public void testFoo() throws Exception {
Class<Runnable> mockClass = (Class<Runnable>) mock(Class.class);
Runnable mockRunnable = mock(Runnable.class);
ClassToTest objectUT = new ClassToTest();
objectUT.setRunnableClass(mockClass);
when(mockClass.newInstance()).thenReturn(mockRunnable);
assertThat(objectUT.foo(), is(sameInstance(mockRunnable);
}
}
How about this. creating a get method of the has a Object (MS) in class PCService and then mock it.
public class PCService implements PCServiceIf {
public MSIf getMS() {
return ms;
}
private MSIf ms = new MS();
public boolean isMovieAccessibleToMyLevel(String myLevel, String movieId) {
return getMS().getPCL(movieId);
}
}
#Test
public void testIsMovieAccessibleToMyLevelMock() {
msMock = mock(MS.class);
spy = spy(new PCService());
doReturn(msMock).when(spy).getMS();
when(msMock.getPCL(movieId)).thenReturn(value);
when(spy.getMS().getPCL(movieId)).thenReturn(value);
assertTrue(spy.isMovieAccessibleToMyLevel("PG", movieId) == true);
}

Mockito - mocking classes with native methods

I have simple test case:
#Test
public void test() throws Exception{
TableElement table = mock(TableElement.class);
table.insertRow(0);
}
Where TableElement is GWT class with method insertRow defined as:
public final native TableRowElement insertRow(int index);
When I launch test I'm getting:
java.lang.UnsatisfiedLinkError: com.google.gwt.dom.client.TableElement.insertRow(I)Lcom/google/gwt/dom/client/TableRowElement;
at com.google.gwt.dom.client.TableElement.insertRow(Native Method)
Which as I believe is related with insertRow method being native. Is there any way or workaround to mock such methods with Mockito?
Mockito itself doesn't seem to be able to mock native methods according to this Google Group thread. However you do have two options:
Wrap the TableElement class in an interface and mock that interface to properly test that your SUT calls the wrapped insertRow(...) method. The drawback is the extra interface that you need to add (when GWT project should've done this in their own API) and the overhead to use it. The code for the interface and the concrete implementation would look like this:
// the mockable interface
public interface ITableElementWrapper {
public void insertRow(int index);
}
// the concrete implementation that you'll be using
public class TableElementWrapper implements ITableElementWrapper {
TableElement wrapped;
public TableElementWrapper(TableElement te) {
this.wrapped = te;
}
public void insertRow(int index) {
wrapped.insertRow(index);
}
}
// the factory that your SUT should be injected with and be
// using to wrap the table element with
public interface IGwtWrapperFactory {
public ITableElementWrapper wrap(TableElement te);
}
public class GwtWrapperFactory implements IGwtWrapperFactory {
public ITableElementWrapper wrap(TableElement te) {
return new TableElementWrapper(te);
}
}
Use Powermock and it's Mockito API extension called PowerMockito to mock the native method. The drawback is that you have another dependency to load into your test project (I'm aware this may be a problem with some organizations where a 3rd party library has to be audited first in order to be used).
Personally I'd go with option 2, as GWT project is not likely to wrap their own classes in interfaces (and it is more likely they have more native methods that needs to be mocked) and doing it for yourself to only wrap a native method call is just waste of your time.
In case anybody else stumbles about this: In the meantime (in May 2013) GwtMockito turned up, which solves this problem without PowerMock's overhead.
Try this
#RunWith(GwtMockitoTestRunner.class)
public class MyTest {
#Test
public void test() throws Exception{
TableElement table = mock(TableElement.class);
table.insertRow(0);
}
}

Guice injector in JUnit tests [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
Using Guice, is it a good practice to get a new injector in each JUnit test class, as each test class should be independant?
In case anyone stumbles upon this question and wants to see how to get Guice annotations working from unit tests, extend your tests from a base class like the one below and call injector.injectMembers(this);
public class TestBase {
protected Injector injector = Guice.createInjector(new AbstractModule() {
#Override
protected void configure() {
bind(HelloService.class);
}
});
#Before
public void setup () {
injector.injectMembers(this);
}
}
Then your test can get an injected HelloService like this
public class HelloServiceTest extends TestBase {
#Inject
HelloService service;
#Test
public void testService() throws Exception {
//Do testing here
}
}
You should really avoid using Guice in unit tests as each test should be small enough that manual DI is manageable. By using Guice (or any DI) in unit tests you are hiding away a warning that your class is getting too big and taking on too many responsibilities.
For testing the bootstrapper code and integration tests then yes create a different injector for each test.
I think using DI will make unit test code more simple, I always Use DI for unit test and also for integration test.
Without DI everything feels hard to code. Either using Guice Inject or Spring Autowired. like my test code bellow:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "/application-context.xml")
public class When_inexists_user_disabled {
#Autowired
IRegistrationService registrationService;
private int userId;
#Before
public void setUp() {
Logger.getRootLogger().setLevel(Level.INFO);
Logger.getLogger("org.springframework").setLevel(Level.WARN);
BasicConfigurator.configure();
userId = 999;
}
#Test(expected=UserNotFoundException.class)
public void user_should_have_disabled() throws UserNotFoundException {
registrationService.disable(userId);
}
}
This depends on which version of JUnit is being used. Our teams have used Junit4 successfully and are now looking into JUnit5.
In Junit5 we use extensions.
public class InjectionPoint implements BeforeTestExecutionCallback {
#Override
public void beforeTestExecution(ExtensionContext context) throws Exception {
List<Module> modules = Lists.newArrayList(new ConfigurationModule());
Optional<Object> test = context.getTestInstance();
if (test.isPresent()) {
RequiresInjection requiresInjection = test.get().getClass().getAnnotation(RequiresInjection.class);
if (requiresInjection != null) {
for (Class c : requiresInjection.values()) {
modules.add((Module) c.newInstance());
}
}
Module aggregate = Modules.combine(modules);
Injector injector = Guice.createInjector(aggregate);
injector.injectMembers(test.get());
getStore(context).put(injector.getClass(), injector);
}
}
private Store getStore(ExtensionContext context) {
return context.getStore(Namespace.create(getClass()));
}
}
Then each test uses the RequiresInjection annotation, which can accept an array of inner modules to aggregate, or none to use the default.
#RequiresInjection
public class Junit5InjectWithoutModuleTest {
#Inject
private TestEnvironment environment;
#Test
public void shouldAccessFromOuterModule() {
assertThat(environment).isNotNull();
}
}
And here's the annotation:
#ExtendWith(InjectionPoint.class)
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
public #interface RequiresInjection {
Class<? extends Module>[] values() default {};
}
JUnit5 is still new to me, so I may be looking into templates, but so far the Extensions seem to do the trick.
With JUnit4 we use a similar approach, except that the injection takes place within the createTest method of our custom test runner, and then each test implements a RequiresInjection interface that has a "getModule" method.
I should probably give a shout out to TestNG as well, as Guice support is built right in. Usage is as simple as this:
#Guice({SomeObjectModule.class})
public class MyTest {
#Inject
SomeObject someObject;
}
Take a look at Guice Berry.
I won't recommend using it now (documentation is really terrible), but looking at their approach can make you think clear about how DI should be done in jUnit.
I found AtUnit to be an excellent complement to Guice (it even deals with mock framework integration).
This makes the Unit Test classes extremely clear and concise (never see an Injector there) and, where appropriate, also lets you exercise your production bindings as part of your unit tests.
I suggest this framework I have recently written Guice-Behave.
It is very simple, with two annotations you can run the test in the same context of your application.
You can define your mocks inside the Guice module and in this way it is very easy to re-use them.

Conditionally ignoring tests in JUnit 4

OK, so the #Ignore annotation is good for marking that a test case shouldn't be run.
However, sometimes I want to ignore a test based on runtime information. An example might be if I have a concurrency test that needs to be run on a machine with a certain number of cores. If this test were run on a uniprocessor machine, I don't think it would be correct to just pass the test (since it hasn't been run), and it certainly wouldn't be right to fail the test and break the build.
So I want to be able to ignore tests at runtime, as this seems like the right outcome (since the test framework will allow the build to pass but record that the tests weren't run). I'm fairly sure that the annotation won't give me this flexibility, and suspect that I'll need to manually create the test suite for the class in question. However, the documentation doesn't mention anything about this and looking through the API it's also not clear how this would be done programmatically (i.e. how do I programatically create an instance of Test or similar that is equivalent to that created by the #Ignore annotation?).
If anyone has done something similar in the past, or has a bright idea of how else I could go about this, I'd be happy to hear about it.
The JUnit way is to do this at run-time is org.junit.Assume.
#Before
public void beforeMethod() {
org.junit.Assume.assumeTrue(someCondition());
// rest of setup.
}
You can do it in a #Before method or in the test itself, but not in an #After method. If you do it in the test itself, your #Before method will get run. You can also do it within #BeforeClass to prevent class initialization.
An assumption failure causes the test to be ignored.
Edit: To compare with the #RunIf annotation from junit-ext, their sample code would look like this:
#Test
public void calculateTotalSalary() {
assumeThat(Database.connect(), is(notNull()));
//test code below.
}
Not to mention that it is much easier to capture and use the connection from the Database.connect() method this way.
You should checkout Junit-ext project. They have RunIf annotation that performs conditional tests, like:
#Test
#RunIf(DatabaseIsConnected.class)
public void calculateTotalSalary() {
//your code there
}
class DatabaseIsConnected implements Checker {
public boolean satisify() {
return Database.connect() != null;
}
}
[Code sample taken from their tutorial]
In JUnit 4, another option for you may be to create an annotation to denote that the test needs to meet your custom criteria, then extend the default runner with your own and using reflection, base your decision on the custom criteria. It may look something like this:
public class CustomRunner extends BlockJUnit4ClassRunner {
public CTRunner(Class<?> klass) throws initializationError {
super(klass);
}
#Override
protected boolean isIgnored(FrameworkMethod child) {
if(shouldIgnore()) {
return true;
}
return super.isIgnored(child);
}
private boolean shouldIgnore(class) {
/* some custom criteria */
}
}
Additionally to the answer of #tkruse and #Yishai:
I do this way to conditionally skip test methods especially for Parameterized tests, if a test method should only run for some test data records.
public class MyTest {
// get current test method
#Rule public TestName testName = new TestName();
#Before
public void setUp() {
org.junit.Assume.assumeTrue(new Function<String, Boolean>() {
#Override
public Boolean apply(String testMethod) {
if (testMethod.startsWith("testMyMethod")) {
return <some condition>;
}
return true;
}
}.apply(testName.getMethodName()));
... continue setup ...
}
}
A quick note: Assume.assumeTrue(condition) ignores rest of the steps but passes the test.
To fail the test, use org.junit.Assert.fail() inside the conditional statement. Works same like Assume.assumeTrue() but fails the test.

Categories

Resources