How to make jUnit class have parameter - java

I have problem with passing a bean class like mvc concept to implement to jUnit class. I don't want change the structure jUnit class, because i have need it.
Class DataBean
public class DataBean {
private String browserName;
private String userName;
public String getBrowserName() {
return browserName;
}
public void setBrowserName(String browserName) {
this.browserName = browserName;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
Class Main
public class Main {
public static void main(String[] args) {
String[] arrBrowserName = {"chrome", "firefox"};
String[] arrUserName = {"user1", "user2"};
for(int i=0; i<2; i++) {
DataBean dataBean = new DataBean();
String browserName = arrBrowserName[i];
String userName = arrUserName[i];
dataBean.setBrowserName(browserName);
dataBean.setUserName(userName);
//How to call "TestCase1", include passing the "databean"
JUnitCore junit = new JUnitCore();
junit.run(TestCase1.class);
}
}
}
Class TestCase1
public class TestCase1 {
DataBean dataBean = new DataBean();
//Here, how to do ? i want to get "databean" from "Main" class, without change this is class as jUnit
#Before
public void setUp(){
//set up based on data from "Main class"
}
#Test
public void scenario(){
//
}
#After
public void tearDown(){
//
}
}
Based on the above code, let's say i have 2 data as data testing, i want setup the before based on the data from Main class. Where is i placement the parameter in TestCase1 so that I can get databean ? and is this possible?

FYI, the DataBean object is a smell called anemic object.
It is a DTO (object to transport data), so except when required by some framework, try to keep these immutable, or at least make it explicit that there is no encapsulation:
public class DataBean {
public String browserName;
public String userName;
}
Anyway, it seems that you are trying to parameterize a test.
Given that the test object is built by JUnit, you will have to change the test class using the API provided by JUnit to inject the needed object/data.
You could use a ThreadLocal storage to bypass the framework API, but I do not recommand it at all.
If you use JUnit, do it the JUnit way.
Assuming that you still use JUnit4, you can go (at least) two ways:
First, using JUnit4 built-in runner Parameterized, making a test class parameterized:
import java.util.Arrays;
import java.util.Collection;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
#RunWith(Parameterized.class)
public class BrowserTest {
#Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
{new DataBean("chrome", "user1")},
{new DataBean("firefox", "user2")}
});
}
private final DataBean dataBean;
public BrowserTest(DataBean dataBean) {
this.dataBean = dataBean;
}
#Test
public void test() {
// Test using a dataBean instance
}
}
Second, use a third library called JUnitParams with the runner JUnitParamsRunner, making a test method parameterized:
import org.junit.Test;
import org.junit.runner.RunWith;
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
#RunWith(JUnitParamsRunner.class)
public class BrowserTest {
#Test
#Parameters(method = "test_cases")
public void test(DataBean dataBean) {
// Test using a dataBean instance
}
public static Object[] test_cases() {
return new Object[]{
new DataBean("chrome", "user1"),
new DataBean("firefox", "user2")
};
}
}
Finally, there is the new version, JUnit5 which changes a lot regarding its extention model as it allows composition of features (instead of having only one runner).
With JUnit5, the same test can be written like this:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
class BrowserTest {
#ParameterizedTest
#CsvSource({
"chrome, user1",
"firefox, user2"
})
void test(String browserName, String userName) {
// Test using a dataBean instance
}
}
Hope this helps !

Related

JUnit setUp doesn't create object

Why do I get a NullPointerExeption for testManuscript when trying to run my test?
This is my Manuscript.java:
package org.lhoffjann;
public class Manuscript {
private String msID;
private String path;
public void setMSid(String msID){
this.msID = msID;
}
public String getMSid() {
return this.msID;
}
}
This is my ManuscriptTest.java:
package org.lhoffjann;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ManuscriptTest {
private static Manuscript testManuscript;
#Before
public void setUp(){
testManuscript = new Manuscript();
}
#Test
public void testGetMSid() {
testManuscript.setMSid("1234");
assertTrue("1234" == testManuscript.getMSid());
}
}
You have imported #Test from JUnit 5, while you're using #Before from JUnit 4, that combination doesn't work. You need to choose which JUnit version you want to use, 4 or 5, and then consistently import classes from that JUnit version. I would recommend using JUnit 5, and removing all JUnit 4 dependencies from your classpath, or at least configure your IDE to not suggest those imports.
For this specific case, replace #Before (org.junit.Before) with #BeforeEach (org.junit.jupiter.api.BeforeEach).
In the example as shown, you don't even need this setUp method, as each test-execution gets its own instance of the test class. You can use:
private Manuscript testManuscript = new Manuscript();
That is, remove static, initialize the field directly, and remove the setUp method.
Even if you continue to use the setUp method, I recommend removing the static, so testManuscript is an instance field, like it is actually used.
You have mixed Junit4 with Junit5. You should use only one version.
Junit4 or
package org.lhoffjann;
import org.junit.Before;
import org.junit.Test;
import org.junit.Assert;
public class ManuscriptTest {
private static Manuscript testManuscript;
#Before
public void setUp(){
testManuscript = new Manuscript();
}
#Test
public void testGetMSid() {
testManuscript.setMSid("1234");
Assert.assertEquals("1234",testManuscript.getMSid());
}
or
Junit5
package org.lhoffjann;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class ManuscriptTest {
private static Manuscript testManuscript;
#BeforeEach
public void setUp() {
testManuscript = new Manuscript();
}
#Test
void testGetMSid() {
testManuscript.setMSid("1234");
Assertions.assertEquals("1234", testManuscript.getMSid());
}
}

Mock static method called from constructor in java class

I want to mock the static method being invoked from the constructor of my class.
My class:
package com.javaeasily.demos.junit;
import java.util.ArrayList;
public class MyClass {
private int number;
private static final ArrayList<String> ACTIVE_SERVICES_POST_RECONFIGURE = new ArrayList<>();
// Only allow construction if number is greater than one
MyClass() {
ACTIVE_SERVICES_POST_RECONFIGURE.add("my-node-" + NodeUtils.getMyNode());
}
public void reconfigureNode() {
if (ACTIVE_SERVICES_POST_RECONFIGURE.isEmpty()) {
return;
}
}
}
Here NodeUtils.getMyNode() is the static method being invoked from the constructor of the class.
NodeUtils.java Class:
package com.javaeasily.demos.junit;
import org.apache.maven.surefire.shade.booter.org.apache.commons.lang3.StringUtils;
public class NodeUtils {
private static final String HOSTNAME_PREFIX = "my-node-";
public static String hostnameToNode(String hostname) {
if (!hostname.startsWith(HOSTNAME_PREFIX)) {
throw new IllegalArgumentException(hostname + " is not recognized hostname");
}
return StringUtils.removeStart(hostname, HOSTNAME_PREFIX);
}
public static String getHostname() {
return System.getenv("HOSTNAME");
}
public static String getMyNode() {
return hostnameToNode(getHostname());
}
}
MyClassTest.java
package com.javaeasily.demos.junit;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class MyClassTest {
private MyClass myclass;
#BeforeEach
public void SetUp() {
myclass = new MyClass();
}
#Test
public void testReconfigureNode() {
myclass.reconfigureNode();
}
}
When I try & run the only test case I get the following error:
java.lang.NullPointerException
at com.javaeasily.demos.junit.NodeUtils.hostnameToNode(NodeUtils.java:8)
at com.javaeasily.demos.junit.NodeUtils.getMyNode(NodeUtils.java:19)
at com.javaeasily.demos.junit.MyClass.<init>(MyClass.java:12)
at com.javaeasily.demos.junit.MyClassTest.SetUp(MyClassTest.java:11)
I am not sure how do we mock the method to avoid this error?
Since I am new to Java I am not able to catch this. Any help here is appreciated.
So to answer your question how to mock a static method: mockito allows this since version 3.8.0. You can find a tutorial here at Baeldung
This allows generating a statically mocked Object for a concrete context, which you can create within a try block. For your case this would look like the following.
Fixed Unit Test
package com.javaeasily.demos.junit;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
#ExtendWith(MockitoExtension.class)
public class MyClassTest {
private MyClass myclass;
#BeforeEach
public void SetUp() {
try (MockedStatic<NodeUtils> nodeUtilsMockedStatic = Mockito.mockStatic(NodeUtils.class)) {
nodeUtilsMockedStatic.when(NodeUtils::getMyNode).thenReturn("foo");
myclass = new MyClass();
}
}
#Test
public void testReconfigureNode() {
myclass.reconfigureNode();
}
}
Mockito dependency
You need mockito with at least version 3.8.0 in your project.
With maven add:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>3.8.0</version>
<scope>test</scope>
</dependency>
With gradle add:
testImplementation group: 'org.mockito', name: 'mockito-inline', version: '3.8.0'

Is there a way to get the list of scenarios that are to be run in the #BeforeClass annotation in cucumber JVM

I have got a requirement to get the list of all the scenarios that are to be executed based on the tag I provided in cucumber Test runner. However I have to get this list before tests start execution.
I know there is a tag called "#BeforeClass" but I am not sure if I can use to get the list of all the scenarios that are going to be run. For example something like this
#BeforeClass
public void intialize(Scenario[] scenario) throws Exception { }
Below is the code for me test runner class
package com.automation.cucumber;
import com.automation.Utils;
import io.cucumber.java.Scenario;
import io.cucumber.testng.*;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import java.io.File;
#CucumberOptions(features = "features/amazon"
,glue="com.automation.cucumber"
,tags = "#tt"
,dryRun = true
, plugin = {"json:target/cucumber-reports/cucumber.json"})
public class CucumberTestRunner extends AbstractTestNGCucumberTests {
static String resultFolder;
#DataProvider(parallel = true)
public Object[][] scenarios() {
return super.scenarios();
}
#BeforeClass
public void intialize() throws Exception {
resultFolder = Utils.createTestReportFolder();
if(resultFolder==null)
{
throw new Exception("Unable to create a result folder");
}
System.out.println();
}
}
You may have to implement EventListener class to get that information and do dryRun = true in your Runner class in #CucumberOptions
Quoting from a question that can help you achieve what you need
public class DryRunPlugin implements EventListener {
#Override
public void setEventPublisher(EventPublisher publisher) {
publisher.registerHandlerFor(TestCaseStarted.class, this::handleCaseStarted);
}
private void handleCaseStarted(TestCaseStarted event) {
System.out.println(event.getTestCase().getUri());
System.out.println(event.getTestCase().getName());
System.out.println(event.getTestCase().getScenarioDesignation());
event.getTestCase().getTags().stream().forEach(t ->
System.out.println(t.getName()));
}
}

mockito when interact with each other in different method

I have a short piece of code and two unit test. Strangely when I launch the test separately they works well but when I launch them together it look like the second method use the "when" of the first method.
Tested method :
public ProductIssuer update(ProductIssuer productIssuer) {
findById(productIssuer.getId())
.orElseThrow(() -> new B4FinanceException(ErrorCode.USER_NOT_FOUND, "Please provide an existing user"));
return productIssuerRepository.save(productIssuer);
}
The tests :
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class ProductIssuerServiceTest {
#InjectMocks
private static ProductIssuerService productIssuerService;
#Mock
private static ProductIssuerRepository productIssuerRepository;
public static final UUID DEFAULT_UUID = UUID.fromString("b8fc499a-2084-11e8-b467-0ed5f89f0000");
private static final String DEFAULT_NAME = "productIssuer Name";
#BeforeEach
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void updateNotFoundThrowException() {
ProductIssuer productIssuer = new ProductIssuer();
productIssuer.setName(DEFAULT_NAME);
when(productIssuerRepository.findById(any())).thenReturn(Optional.empty());
assertThatExceptionOfType(B4FinanceException.class).isThrownBy(() -> productIssuerService.update(productIssuer));
}
#Test
public void update() {
ProductIssuer productIssuer = new ProductIssuer();
productIssuer.setName(DEFAULT_NAME);
productIssuer.setId(DEFAULT_UUID);
when(productIssuerRepository.findById(any())).thenReturn(Optional.of(productIssuer));
when(productIssuerRepository.save(any())).thenReturn(productIssuer);
productIssuerService.update(productIssuer);
}
}
The result is ok for the first test (updateNotFoundThrowException) but for the second test I got a "Please provide an existing user" error.

Verifiyng behavior of mock type without instance controlling

I'm developing custom runner of JUnit for internal purposes and, for instance, I've introduced custom annotation for test methods which on applying should make my runner to run method with this annotation after all other test methods without this annotation.
I want to write junit test to verify behavior of my custom runner.
Test class:
public class TestClass {
#Test
#CustomAnnotation
public void test1() {
System.out.println("test1");
}
#Test
public void test2() {
System.out.println("test2");
}
}
An abstract code that will test my runner:
public class MyCustomRunnerTest {
#Test
public void order() throws InitializationError {
// Arrange
// Some code of mocking library might be placed here
// Act
MyCustomRunner runner = new MyCustomRunner(TestClass.class);
runner.run(new RunNotifier());
// Assert
// Here I want to verify that method test1() has been called
// after method test2()
}
}
Is there any mocking libraries that will allow me to perform such verification? Or may be is there any other way to check that?
Why do you not extract the logic that determines the run order of test methods into a separate class or method? This method should return a list of test method names (or other descriptors) in order in which they will run. Then your testing will come down to passing it the test class and asserting that the output is { "test2", "test1" }. No mocking required.
A Better Solution
Use RunListener to log test methods as they are being run by your runner. You of course will have your own MyCustomRunner class, but the rest of the code can stay as in the example below:
import static org.hamcrest.Matchers.contains;
import static org.junit.Assert.assertThat;
import java.util.ArrayList;
import java.util.Collection;
import org.junit.Test;
import org.junit.runner.Description;
import org.junit.runner.RunWith;
import org.junit.runner.notification.RunListener;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;
#RunWith(BlockJUnit4ClassRunner.class)
public class RunnerTest {
// dummy "custom" test runner
public static class MyCustomRunner extends BlockJUnit4ClassRunner {
public MyCustomRunner(Class<?> klass) throws InitializationError {
super(klass);
}
}
public static class TestClass {
#Test
public void test1() {}
#Test
public void test2() {}
}
#Test
public void myCustomRunnerExecutesTestsInOrder() throws InitializationError {
RunNotifier notifier = new RunNotifier();
Collection<String> runTestMethods = new ArrayList<>();
notifier.addListener(new RunListener() {
#Override
public void testStarted(Description description) throws Exception {
runTestMethods.add(description.getMethodName());
}
});
new MyCustomRunner(TestClass.class).run(notifier);
// assert that the collection contains methods names in the specified order
assertThat(runTestMethods, contains("test1", "test2"));
}
}

Categories

Resources