Difference in running Cucumber-JVM vs Cucumber runner(Junit) - junit

I am fairly new to Cucumber. I was experimenting with it by just creating few test features when I noticed the difference when running a single feature vs running the whole suite (from the IntelliJ).
I noticed that when I run single feature it runs using the cucumber-jvm option and in this case, the CucumberConfig(the blank class to define the runner and cucumber options) and the Runner is not utilized. However, when I run the whole suite it runs as a JUnit test and obviously, in this case, the Config class and the runner comes into the picture.
I confirmed this with the following sample code:
#RunWith(CustomRunner.class)
#CucumberOptions()
public class CucumberConfig {
#BeforeClass
public static void beforeClass()
{
System.out.println("This is run before Once: ");
}
#AfterClass
public static void afterClass()
{
System.out.println("This is run after Once: ");
}
}
CustomRunner
public class CustomRunner extends Cucumber {
public CustomRunner(Class clazz) throws InitializationError, IOException {
super(clazz);
System.out.println("I am in the custom runner.");
}
}
Also, I understand that while running as cucumber-junit we can't pass specific feature to run as in cucumber-jvm. Correct me if I am wrong.
My doubt is, is this the default behavior or am I doing something wrong. And, if this is default how can I make cucumber to always use the Config file.
I'll appreciate if someone can provide some insight on this.

When you're using IntelliJ IDEA to run the tests, IDEA will use cucumber.api.Main to run the tests. As such it will ignore CucumberConfig neither will it run #BeforeClass nor #AfterClass, these are only used by the JUnit runner.

Related

Is there a way to share #Before code between tests suite classes?

I am testing a Cordova plugin in Java/Android and I need to initialize my Plugin class and set some state before I run my Tests.
#Before
public void beforeEach() throws Exception {
System.out.println("Creating new Instance ");
PowerMockito.mockStatic(Helpers.class);
PowerMockito.when(Helpers.canUseStorage(any(), any())).thenReturn(true);
MyLogger myLoggerMock = PowerMockito.mock(MyLogger.class);
PowerMockito.doNothing().when(myLoggerMock, "log", anyString());
PowerMockito.whenNew(MyLogger.class).withAnyArguments().thenReturn(myLoggerMock);
this.sut = spy(new FilePicker());
PowerMockito.doNothing().when(this.sut).pick(any(), any());
}
I want to create a Test Suite / Java Class per public function, but I do not want to repeat that code every time.
Is there a way to share that before each between test suites? I have found ClassRule but I think I do not do what I need (or I am understanding it wrong... I am really new in Java)
In Typescript we can share beforeEachfunctions with several suites, and each suite can have their own beforeEach
One possible ways is using inheritance:
Make all test classes extend from one "parent test" class and define a #Before in a parent class.
So it will be called automatically for all the subclasses:
public class ParentTest {
#Before
public void doInitialization() {
....
}
}
public class Test1Class extends ParentClass {
#Test
public void fooTest() {
// doInitialization will be executed before this method
}
#Test
public void barTest() {
// doInitialization will be executed before this method as well
}
}
Two notes:
Note 1
In the code you use sut (subject under test) - this obviously should not be in the parent's doInitialization method, so its possible that Test1Class will also have methods annotated with #Before (read here for information about ordering and so forth)
Then the `sut gets initialized with Spy which is frankly weird IMHO, the Subject Under Test should be a real class that you wrote, but that's beyond the scope of the question, just mentioning it because it can point on mistake.
Note 2
I'm writing it in an an attempt to help because you've said that you're new in Java, this is not strictly related to your question...
While this approach works in general you should be really cautious with PowerMockito. I'm not a PowerMockito expert and try to avoid this type of mocks in my code but in a nutshell the way it manipulates the byte code can clash with other tools. From your code: you can refactor the HelperUtils to be non-static and thus avoid PowerMocking in favor of regular mocking which is faster and much more safe.
As for the Logging - usually you can compromise on it in unit test, if you're using slf4j library you can config it to use "no-op" log for tests, like sending all the logging messages into "nothing", and not-seeing them in the console.

Launching JUnit jupiter tests from inside a main method?

I have a Java class with a main method that I invoke to occasionally run some tests. Specifically, I'm trying to come up with a solution for quickly testing various code snippets that use the AWS SDK to create/read some S3 objects. I'm not really trying to build regular unit/integration tests, and I'm not interested in mocking the S3 code. I'm trying to quickly develop/debug some code using a test framework. I found the following SO question, and the answer about using JUnit5 Jupiter's Launcher and it intrigued me:
How do I run JUnit tests from inside my java application?
So I read the Junit5 chapter on the Launcher API and followed the example code. I came up with something like this:
class S3ManualTest {
public static void main(String[] args) {
LauncherDiscoveryRequest request =
LauncherDiscoveryRequestBuilder
.request()
.selectors(selectPackage("com.xyz.s3util"),
selectClass(S3ManualTest.class),
selectMethod(S3ManualTest.class, "happyPath")
)
.build();
Launcher launcher = LauncherFactory.create();
SummaryGeneratingListener listener = new SummaryGeneratingListener();
launcher.execute(request, listener);
TestExecutionSummary summary = listener.getSummary();
System.out.println("# of containers found: " + summary.getContainersFoundCount());
System.out.println("# of containers skipped: " + summary.getContainersSkippedCount());
System.out.println("# of tests found: " + summary.getTestsFoundCount());
System.out.println("# of tests skipped: " + summary.getTestsSkippedCount());
}
void happyPath() {
assertTrue(true); // Do useful stuff here
}
}
The launcher doesn't find any tests to run, even though I specifically selected the "happyPath" method. I have tried annotating the happyPath() method with #Test, and that seems to work, but it also has the undesired side effect that the method gets executed if I run all tests in that package, either from gradle, or from inside the IDE. Essentially, I want my test methods to be invoked with the JUnit5 framework, but only when I manually run the main method in the class. I was thinking about some custom annotations, or implementing some interface that would get picked up by the test engine, but haven't gone down that route yet. I'm guessing there's some easy way of accomplishing what I'm trying to do. Thanks.
I could only find a work around: disabling the happyPath() test method by default and override it in your program like explained here: https://junit.org/junit5/docs/current/user-guide/#extensions-conditions-deactivation
#Test
#Disabled
void happyPath() {
assertTrue(true); // Do useful stuff here
}
And in your launcher setup, deactivate the DisabledCondition:
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder
.request()
.selectors(selectMethod(S3ManualTest.class, "happyPath"))
.configurationParameter(
"junit.jupiter.conditions.deactivate",
"org.junit.*DisabledCondition")
.build();
You may also specify a dedicated switch, if you don't want deactivate DisabledCondition for the entire run:
#Test
#EnabledIf("'true'.equals(junitConfigurationParameter.get('manual'))")
void happyPath() {
assertTrue(true); // Do useful stuff here
}
with
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder
...
.configurationParameter("manual", "true")
.build();
The second work-around, if applied to more then a few methods, screams for a dedicated ExecutionCondition extension. See details at https://junit.org/junit5/docs/current/user-guide/#writing-tests-conditional-execution-scripts

Execute code before #Before method for JUnit test

I need to execute some code before the #Before method of each unit test is executed. The problem is that I also need to know which test (the name is sufficient) will be executed afterwards.
I can either use AspectJ or Java Agents with bytecode manipulation to achieve this. Also the solution should work for tests where there is no #Before annotation present.
Any ideas?
EDIT: I can't modify the unit tests themselves, as I'm developing a framework for executing tests of other projects
You might want to look into the TestName rule in JUnit:
http://junit.org/junit4/javadoc/4.12/org/junit/rules/TestName.html
About the ordering, a solution could be to define a super class for your tests and put a #Before in there, as #Before methods in super classes are run before those in sub classes.
If you want to write a Java agent and you are not bound to Javassist or AspectJ, have a look at Byte Buddy for doing so. You can add the code in the MyAdvice class to any method annotated with #Test given that the type name ends with Test (as an example) by:
public class MyAgent {
public static void premain(String arg, Instrumentation inst) {
new AgentBuilder.Default()
.type(nameEndsWith("Test"))
.transform((type, cl, builder) -> builder.visit(Advice
.to(MyAdvice.class)
.on(isAnnotatedWith(Test.class)))
.installOn(instrumentation);
}
}
class MyAdvice {
#Advice.OnMethodEnter
static void enter() {
System.out.println("foo");
}
}
Just bundle the above code to a Javaagent with the proper manifest code and register it before running. If you are running on a JDK, you can also attach the agent programmatically using the byte-buddy-agent project.

Problems Testing Sling Model with Custom Injectors

I've been doing some work with sling models for a project and in the process created a couple of custom injectors. Everything seems to work great when implemented (used in AEM). However, when I'm testing the custom injectors are not getting run.
Here's an example of what I currently have set up
In MyModel
#Inheritable
#CustomAnnotation("foo")
private String _foo
In test (tests using wcm.io mocking Libraries)
#Rule
AemContext context = new AemContext(ResourceResolverType.RESOURCERESOLVER_MOCK);
//required by the injector
#Mock
InheritanceService _inheritanceService;
#Mock
InheritableInjector _inheritanceInjector;
#Before
public void setup() {
context.registerService(InheritanceService.class, _inheritanceService);
context.registerService(InheritableInjector.class, _inheritanceInjector);
context.addModelsForPackage("com.package.example.models");
//use this resource in tests to adaptTo(MyModel.class)
_resource = context.load().json("myJson.json", "/myPath");
}
... tests
The tests compile and run, but the Injector isn't being executed. I know it's registered because when I don't have the Injector's dependent services registered in the context I get an error. When I debug through it, none of the breakpoints are hit. I'm wondering if I need to also register the "Inheritable" annotation somewhere or if anyone just has any general information on how I can get the custom injector to execute.
thank you
I was able to figure out my error. So the important thing to remember about Sling Model Injectors is that they are just OSGI services (something I completely let myself get away from).
So just treating them like normal services and then remembering to annotate the Injector with #InjectMocks was what I needed to do in order to fix the error.
The following now works great.
#Mock
InheritanceService _inheritanceService; //injector dependency
#InjectMocks
InheritanceInjector _inheritanceInjector;
#Before
public void setup() {
context.registerService(InheritanceService.class, _inheritanceService);
context.registerService(InheritableInjector.class, _inheritanceInjector);
}
hopefully that helps anyone that might run into the issue. If anyone can make this answer better please feel free to reply/edit.

TestNG java.net.SocketException

I'm attempting to run TestNG tests but I keep getting a java.net.SocketException. Other forums state that this is a known issue for users running TestNG 6.4 and greater on IDEA but I am using Eclipse. I tried reinstalling TestNG to eclipse but that did not help. Furthermore TestNG is failing to report which tests have passed and which have failed. Below is the code that is causing this Exception and notice that the test method is actually empty.
public class AdminUITest extends AccountingTS{
#BeforeClass
public void oneTimeSetUp() {
}
#AfterClass
public void oneTimeTearDown(){
driver.quit();
// closeJSchSessions();
}
#BeforeMethod
public void setUp(Method method){
resetStep();
printStep("TEST CASE >>> "+method.getName());
}
#Test
public void test()
{
}
}
I resolved this in Eclipse by clicking on Windows>Preferences>Java>Installed JREs>Edit and changing the JRE Home to C:\Program Files\Java\jdk1.7.0_10.
If you installed TestNG from eclipse then go to your project properties, click TestNG and uncheck Use project TestNG jar.
Please don't include TestNG jar explicitly in your project's build path, doing so lead to confusion and exception.