Using JUnit with Groovy classloader - java

I have a simple Groovy test class using JUnit
class GroovyJunitTest {
#Test
void test() {
println this.class.getClassLoader().toString()
}
}
This prints out
sun.misc.Launcher$AppClassLoader#4e25154f
which means that Java classloader is used.
I run the test with both Intellij IDE and using gradle test. The same result is in both cases.
Is there a way to configure JUnit to use Groovy classloader?

Once I had the same problem and I used https://github.com/bitstrings/junit-clptr
to load my custom classloader.
Note: this is no longer supported by the crator however for me it did work out. Anyway if it's to important to trust an outside source you can take it as an inspiration and define your own annotation that will let you choose your custom classloader

Related

Why classes loaded with boot classloader (bootclasspath) doesn't include annotations

I was writing unit tests for my javaagent but faced with behavior of JVM I guess which I wasn't aware before and I curious if there is any explanation or article about it. I tried google it and search on SO but with no success.
I found that classes which are included into boot classpath doesn't have annotations with them. To demonstrate it I created a simple JUnit test
import org.junit.Test;
public class SimpleTest {
#Test
public void myTest() {
}
}
It perfectly runs of course :) but if I configure eclipse project like this:
Then it fails with java.lang.Exception: No runnable methods. I see in the debugger that code which checks annotations cannot find them.
I found answer on SO to my question which is perfectly explains what is going on (I voted up there).
https://stackoverflow.com/a/23502439/2013497
JUnit library is added by Eclipse and it goes to regular classpath whenever bootloaded classes doesn't have a way to reference them.

Integrating TestNG with Cucumber Selenium Java

Is there any way to integrate cucumber with existing testng project? Currently, in our project we are using testng with Page object model. Now we decided to include Cucumber also. But i think we cant , because cucumber uses feature file where we can have 'n' number of scenarios. But testng its running based on #test methods.
So, let me know if we can integrate cucumber + testng and if so, how we can run each and every #test methods using cucumber.
Running cucumber scenarios/features using TestNG runner is possible and it adds value, but reverse is not. What you want to achieve by running TestNG with cucumber runner? If you want to have descriptive step level report with existing TestNG test you can start using QAF.
Yes. You can integrate Cucumber JVM + Test NG.
You can use the Cucumber JVM at the #Test Method of TestNG. Do not use Main.main of the Cucumber API since there's a System.exit(0) at the end. Instead you can use Main.run of the Cucumber.
Call the run method in Test method.
Main.main(new String[]{"-g", "package", "path of feature file"}, ClassLoader.getClassLoader);
The run method requires a classLoader, so generate your own classloader if required.
public static byte run(String[] argv, ClassLoader classLoader) throws IOException {
RuntimeOptions runtimeOptions = new RuntimeOptions(new ArrayList<String>(asList(argv)));
ResourceLoader resourceLoader = new MultiLoader(classLoader);
ClassFinder classFinder = new ResourceLoaderClassFinder(resourceLoader, classLoader);
Runtime runtime = new Runtime(resourceLoader, classFinder, classLoader, runtimeOptions);
runtime.run();
return runtime.exitStatus();
}
You can also create your own classLoader to run the main method.

Mock final class with Mockito 2

I'm removing Powermock from the project I'm currently working on, so I'm trying to rewrite some existing unitary test only with Mockito (mockito-core-2.2.28).
When I run the test, I have the following error:
org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class com.ExternalpackagePath.Externalclass
Mockito cannot mock/spy because :
final class
I know that this question has already been asked (How to mock a final class with mockito, Mock objects calling final classes static methods with Mockito), but I didn't find the answer I'm looking for.
Here is an extract of my code :
public class MyClassToTest extends TestCase {
private MyClass myClass;
#Mock private Externalclass ext; // This class is final, I would like to mock it
#Override
protected void setUp() throws Exception {
MockitoAnnotations.initMocks(this); // <<<< The exception is thrown here
ext = Mockito.mock(Externalclass.class);
}
}
As mentioned in the Mockito documentation (https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2, §Mock the unmockable), I added the org.mockito.plugins.MockMaker file. This is the tree of my project :
project
src
com.packagePath.myPackage
myClass
test
com.packagePath.myPackage
myClassToTest
resources
mockito-extensions
org.mockito.plugins.MockMaker
I also tries to put the "resources" directory in "src", in a subdir called "test", but the result is still the same.
I thought that mocking a final was possible with Mockito v2. Does someone have an idea of what is missing here ?
Thanks!
Weird that your solution seems to work.
According to their documentation on Github it says.
Mocking of final classes and methods is an incubating, opt-in feature. It uses a combination of Java agent instrumentation and subclassing in order to enable mockability of these types. As this works differently to our current mechanism and this one has different limitations and as we want to gather experience and user feedback, this feature had to be explicitly activated to be available ; it can be done via the mockito extension mechanism by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:
mock-maker-inline
After you created this file, Mockito will automatically use this new engine and one can do :
final class FinalClass {
final String finalMethod() { return "something"; }
}
FinalClass concrete = new FinalClass();
FinalClass mock = mock(FinalClass.class);
given(mock.finalMethod()).willReturn("not anymore");
assertThat(mock.finalMethod()).isNotEqualTo(concrete.finalMethod());
In subsequent milestones, the team will bring a programmatic way of using this feature. We will identify and provide support for all unmockable scenarios. Stay tuned and please let us know what you think of this feature!
My working structure now looks like this.
I couldn't get it working with the configuration file either; however, the Mockito team is so kind and also provides a pre-configured Mockito artifact that requires no configuration in the target project.
As a convenience, the Mockito team provides an artifact where this mock maker is preconfigured. Instead of using the mockito-core artifact, include the mockito-inline artifact in your project. Note that this artifact is likely to be discontinued once mocking of final classes and methods gets integrated into the default mock maker.
So, if you use Gradle and want to test your Kotlin code, just add this to your project's dependencies:
testCompile 'org.mockito:mockito-inline:2.8.9'
testCompile('com.nhaarman:mockito-kotlin:1.5.0') {
exclude group: 'org.jetbrains.kotlin'
exclude group: 'org.mockito'
}
Well, I found what's wrong here, it maybe useful for other people. My project tree is wrong, I put the org.mockito.plugins.MockMaker in a directory "mockito-extension" directly in "src". This is my tree now:
projet
src
com.packagePath.myPackage
myClass
mockito-extensions
org.mockito.plugins.MockMaker
test
com.packagePath.myPackage
myClassToTest
You seem to have had a classpath issue, just like I did.
Your previous setup would have also worked, but it seems like
project/test/resources
was not in your classpath.
I had the same issue when I tried to run this with IntelliJ. I simply marked the resources directory as a Test Resources Root and it worked fine. Praise the gods of Mockito!
I had the same issue that you described. For me, the solution was to create a file named org.mockito.plugins.MockMaker in /test/java/resources/mockito-extensions/ directory and write the following line: mock-maker-inline.
So MockMaker is actually the file extension (no txt, properties or any other extension needed).
I also encountered the same issue.
This worked for me: How to use the Mockito's inline mock maker: Option 2
Before Mockito can be used for mocking final classes and methods, it needs to be configured. Based on your screenshot of your project tree, it seems that the location of MockMaker file is incorrect.
Create (if the file still does not exist) or update MockMaker file in the path below
src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
... and add this line mock-maker-inline.
If you have multiple modules in project check out if they also have some references to Mockito. For me the problem was deprecated and unnecessary definition in some other small and forgotten library module:
testCompile 'org.mockito:mockito-all:1.10.19'
Removing this unnecessary declaration solved the problem for me
After following configuration instruction, I still wasn't able to get it working.
For me it was due to JDK I was using. After switching to a different one (different provider) the solution with org.mockito.plugins.MockMaker file worked.
I went from JDK with Hotswap agent (trava-jdk-11-dcevm / dcevm-11.0.11+1) to Eclipse adoptOpenJDK (temurin-11.0.14).
This solution worked for me:
Instead of
testCompile "org.mockito:mockito-android:2.9.0"
in the gradle file, replace it with
testCompile group: 'org.mockito', name: 'mockito-inline', version: '2.9.0'
and it would work.

Custom JUnit test detection using gradle

Our test suite is growing quickly and we have reached a point where our more functional tests are dependent on other systems.
We use gradle test tasks to run these tests using the include and exclude filters but this is becoming cumbersome because we are having to name our tests in a particular way.
Our current approach is to name our tests in the following way:
class AppleSingleServiceTest {}
class BananaMultiServiceTest {}
class KiwiIntegrationTest {}
and then include tests in the relevant task using
include '**/*SingleServiceTest.class'
include '**/*MultiServiceTest.class'
include '**/*IntegrationTest.class'
Is it possible find test classes in gradle by looking at annotations?
#SingleServiceTest
public class AppleTest {}
I think any tests that are not annotated would then be run as normal unit tests, so if you forget to annotate a more functional test it will fail
An example of a single service test is a selenium test where any external dependencies of the SUT are stubbed
An example of a multi service test is one where some but maybe not all external dependencies are not stubbed
As of Gradle 1.6, Gradle supports selecting tests with JUnit #Category, like this:
test {
useJUnit {
includeCategories 'org.gradle.junit.CategoryA'
excludeCategories 'org.gradle.junit.CategoryB'
}
}
More details can be found in the docs.
The feature you are asking for doesn't currently exist, but you can make a feature request at http://forums.gradle.org. Or you can use the (cumbersome) JUnit #Category, which requires you to define test suites.
I had a similar need to filter tests with annotations. I eventually managed to create a solution. It is posted here.

Names for dynamically generated TestNG tests in Eclipse plugin

I converted a dynamically generated JUnit test suite to TestNG using a #Factory annotation. The tests are generated by scanning a directory that contains several test specification files (written in a DSL) and by loading them in an test class that knows how to execute them. The test class has a single #Test method named test, implements org.testng.ITest and overrides getTestName() as recommended.
However, in the TestNG Eclipse UI, only the factory and a single execution of test is shown (although it is executed several times, as expected). With JUnit, I had the name of each spec listed as a separate test. This is very important because several test specs could fail and I would need to see all failures (which does not work in the TestNG Eclipse UI for me).
How can I achieve something similar with TestNG? I use the Eclipse TestNG plugin 6.7.0 and testng 6.7.
Try extending XmlTest in your test class and call setName(). I extended XmlSuite and used setName to name my "test suite" which is a class with multiple tests defined in it and that worked for me. In fact I just tried what I suggested on the same class and now it's called a test with the correct name. I'm not sure why the ITest interface is being ignored as I also tried that approach without success.
As carlin.scott suggested, extending XmlTest works for this problem. However, I overrode toString() to return the test name (instead of calling setName). This has the advantage that the test name in the TestNG view is easier to read. By default, it contains additional information such as parameters and metagroups.

Categories

Resources