How to unit test java main method? - java

I have a class to which I must pass 2 arguments through its main method, if passed less than 2 args, it displays a system error message. I wrote a unit test for the main method here, when I run the test, it stops at "running" (shows neither pass nor fail). Please suggest.
Example.java
public class Example
{
private static String str1 = null;
private static String str2 = null;
public static void main(String[] args)
{
if( args.length != 2 )
{
call();
}
Example ex = new Example(args[0], args[1]);
ex.getData();
}
public Example(String str1, String str2)
{
Example.str1 = str1;
Example.str2 = str2;
}
public void getData(){
System.out.println("Name is: "+str1);
System.out.println("City is: "+str2);
}
private static void call()
{
System.err.println("Usage: String1 String2");
System.err.println("Where: ");
System.err.println(" String1 - Name");
System.err.println(" String1 - City");
System.exit(1);
}
}
ExampleTest.java
public class ExampleTest {
#Test
public void testPassingWrongNumberOfInputs() {
StringBuffer sb = new StringBuffer();
sb.append("Usage: String1 String2")
.append("Where: ")
.append(" String1 - Name")
.append(" String1 - City");
String expectedErrorMessage = sb.toString();
ByteArrayOutputStream outContent = new ByteArrayOutputStream();
System.setErr(new PrintStream(outContent));
String[] args = {"one"};
Example.main(args);
assertEquals(expectedErrorMessage, outContent.toString());
}
}

How about the following:
class TestingSecurityManager extends SecurityManager {
#Override public void checkExit(int status) {
throw new SecurityException();
}
}
Then in your test...
public class ExampleTest {
#Test
public void testPassingWrongNumberOfInputs() {
StringBuffer sb = new StringBuffer();
sb.append("Usage: String1 String2")
.append("Where: ")
.append(" String1 - Name")
.append(" String1 - City");
String expectedErrorMessage = sb.toString();
ByteArrayOutputStream outContent = new ByteArrayOutputStream();
System.setErr(new PrintStream(outContent));
String[] args = {"one"};
TestSecurityManager sm = new TestSecurityManager ();
System.setSecurityManager(sm);
try {
Example.main(args);
//should throw
fail("Should have thrown exception");
} catch (SecurityException se) {
}
assertEquals(expectedErrorMessage, outContent.toString());
}
}

I finally was able to write the unit test as shown in the following. I only tested if the method is hitting System.exit(1) code or not.
public class ExampleTest {
private SecurityManager m;
private TestSecurityManager sm;
#Before
public void setUp()
{
m = System.getSecurityManager();
sm = new TestSecurityManager ();
System.setSecurityManager(sm);
}
#After
public void tearDown()
{
System.setSecurityManager(m);
}
#Test
public void testPassingWrongNumberOfInputs() {
try {
Example.main(new String[] {"one"});
} catch (SecurityException se) {
assertEquals("1", se.getMessage());
}
}
}
class TestSecurityManager extends SecurityManager {
#Override
public void checkPermission(Permission permission) {
if ("exitVM".equals(permission.getName()))
{
throw new SecurityException("System.exit attempted and blocked.");
}
}
#Override
public void checkExit(int status) {
throw new SecurityException(Integer.toString(status));
}
}

Remove the System.exit(1) call, you don't need it. Your app will exit after main() completes anyway without an unneeded call to explicitly terminate the VM. This call is most likely causing your JUnit to stop executing before you get to your assertEquals statement, because you just told the VM to quit.

Rename the main method, and add a return value, so you can test it. Call this new method from main.

Related

TestNG run multiple tests with data from same ArrayList using Java

I just started to use TestNG and have a problem with tests. After populating the ArrayList I try to get the first element and after removing it(queue like), but all tests look like work parallel because each test gets the same element, I mean that the second test starts working before the first test remove the element from ArrayList.
Lab1Main inst = new Lab1Main();
ArrayList<String> assets;
/**
* Method for reading input from the console
* reads only 2 times
* #return ArrayList<String>
*/
private ArrayList<String> input() {
assets = new ArrayList<String>();
Scanner scan = new Scanner(System.in);
System.out.println("type your data and press enter at ther end");
String line = scan.nextLine();
assets.add(line);
int count = 0;
while (count < 1) {
line = scan.nextLine();
assets.add(line);
count++;
}
scan.close();
System.out.println("Scanner closed" + assets);
return assets;
}
/**
* Test will pass or fail depends on input data
* if input String length less than 3(str.length<3) test will fail
* because mutator(setStr) in class Lab1Main will throws an error and won't initialize the variable
*/
#Test
public void firstTest() {
try {
inst.setStr(assets.get(0));
} catch (StringIndexOutOfBoundsException e) {
System.out.println(e);
} finally {
Assert.assertEquals(inst.getStr(), assets.get(0));
assets.remove(0);
}
}
#Test
public void secondtTest() {
try {
inst.setStr(assets.get(0));
} catch (StringIndexOutOfBoundsException e) {
System.out.println(e);
} finally {
Assert.assertEquals(inst.getStr(), assets.get(0));
assets.remove(0);
}
}
#BeforeTest
public void beforeTest() {
assets = input();
}
#AfterTest
public void afterTest() {
}
}
Class for testing
private String str;
public Lab1Main() {
// TODO Auto-generated constructor stub
}
public String getStr() {
return str;
}
/**
* throws error if input string length<3
* #param str
* #throws StringIndexOutOfBoundsException
*/
public void setStr(String str) throws StringIndexOutOfBoundsException {
if (str.length() < 3) {
throw new StringIndexOutOfBoundsException(
"Input string has to has length > 2 your lenght is " + str.length());
} else {
this.str = str;
}
}
}
Thank you!
I mean that the second test starts working before the first test remove the element from ArrayList
Order of tests execution is not guaranteed in TestNG. But there is a parameter called dependsOnMethods that you can use to order your tests like so:
#Test
public void firstTest() {
//first testcase
}
#Test(dependsOnMethods="firstTest")
public void secondTest() {
//second testcase
}
#Test(dependsOnMethods="secondTest")
public void thirdTest() {
//third testcase
}
See TestNG doc for more details. (Do a search for word dependsOnMethods in the link)
I can't say that it's answered my question but it's the way to solve this problem
public Object[][] sendData() {
return new Object[][] { { assets.get(0) }, { assets.get(1) } };
}
/**
* Test will pass or fail depends on input data if input String length less than
* 3(str.length<3) test will fail because mutator(setStr) in class Lab1Main will
* throws an error and won't initialize the variable
*/
#Test(dataProvider="sendData")
public void firstTest(String data) {
try {
inst.setStr(data);
} catch (StringIndexOutOfBoundsException e) {
System.out.println(e);
} finally {
Assert.assertEquals(inst.getStr(), data);
}
}

Is there another method to replace Exception message with custom message instead of try{}catch(Exception e){} method?

Instead of the try{}catch(Exception e){} method, is there a way to just state a custom message that replaces the exception message when exceptions like InputMismatchException, NoSuchElementException etc. occurs anywhere on the program?
EDIT: I want another method because if I use try{}catch(Exception e){} method than I will have to do it everywhere and the code also becomes longer.
For example:
public static String genderOutput()
{
try
{
System.out.print("\nMale - 1 \nFemale - 2 \n\nEnter either 1 or 2: ");
int genderInput = userInput.nextInt();
if(genderInput == 1)
{
String userGender = "Mr.";
return userGender;
}
else if(genderInput == 2)
{
String userGender = "Mrs.";
return userGender;
}
else
{
String userGender = " ";
return userGender;
}
}
catch (Exception e)
{
return null;
}
}
I have this function, now if there were multiple functions in a class like this then I would have to have the try{}catch(Exception e){} method everywhere. Wouldn't it be more efficient if you can just replace the exception message with your own and when such exception occurs which has a custom message stated to them then it would just throw out the custom message instead. This way, the code will be shorter as well.
SOLUTION TO MY PROBLEM:
public class Test
{
public static Scanner userInput = new Scanner(System.in);
public static String titleName = "TheRivalsRage";
public static String exitLevelMessage = "Program exited!";
public static String errorMessageTitle = "\n[Error] ";
public static String intInputMismatchException = "Please enter an Integer Value!";
public static String intNoSuchElementException = "Please enter either '1' or '2' without the quotes!";
public static String lineNoSuchElementException = "Please enter something!";
public static String bothIllegalStateException = "Scanner closed unexpectedly!";
public static void main(String[] args)
throws Exception
{
String usernameOutput;
String userGender;
try
{
System.out.print("Enter your username: ");
usernameOutput = userInput.nextLine();
userGender = genderOutput();
userInput.close();
}
catch(IllegalStateException e)
{
throw new IllegalStateException(errorMessageTitle + bothIllegalStateException);
}
if(userGender == null)
{
noSuchElementException();
}
else
{
System.out.println("\nWelcome " + userGender + " " + usernameOutput + " to " + titleName);
}
}
public static String genderOutput()
{
String userGender;
int genderInput;
System.out.print("\nMale - 1 \nFemale - 2 \n\nEnter either 1 or 2: ");
try
{
genderInput = userInput.nextInt();
}
catch(InputMismatchException e)
{
genderInput = 0;
inputMismatchException();
}
if(genderInput == 1)
{
userGender = "Mr.";
}
else if(genderInput == 2)
{
userGender = "Mrs.";
}
else
{
userGender = null;
}
return userGender;
}
public static void inputMismatchException()
throws InputMismatchException
{
throw new InputMismatchException(errorMessageTitle + intInputMismatchException);
}
public static void noSuchElementException()
throws NoSuchElementException
{
throw new NoSuchElementException(errorMessageTitle + intNoSuchElementException);
}
}
don't handle exception in each and every method just use throws Exception after method signature and handle it at end where the methods are being called.
and there in catch block you can throw your custom exception.
void method1() throws Exception{
//
}
void method2() throws Exception{
//
}
void finalmethod(){
try{
method1();
method2();
}catch(InputMismatchException e){
throw customExcpetion("custommessage1");
}catch(Exception e){
throw customExcpetion("custommessage2");
}
}
You need a try/catch.
However, you do not need to catch all exceptions separately, because the exceptions that you mention are all subclasses of RuntimeException. Hence, it is sufficient to make a single try/catch in your main to intercept RuntimeException, and print the replacement message:
public static void main(String[] args) {
try {
... // Actual code
} catch (RuntimeException ex) {
System.err.println("A runtime error has occurred.");
}
}
You can try Aspectj or Spring aop by creating around advice. You can replace message by catching exception inside advice and rethrow.
Check http://howtodoinjava.com/spring/spring-aop/aspectj-around-advice-example/
To know about how to use spring aop for anound advice
Java doesn't provide this feature out of the box but nobody prevents you to create a class that composes a Scanner object and that decorates methods that you are using as nextInt().
Inside the decorated method, invoke nextInt(), catch the exception that it may throw and handle it by returning null as in your question.
If it makes sense, you could even provide a nextInt() method with a default value as parameter if the input fails.
public class MyCustomScanner{
private Scanner scanner;
...
public Integer nextInt(){
try{
return scanner.nextInt()
}
catch(InputMismatchException e){
myStateObj.setErrorMessage("....");
return null;
}
}
public Integer nextInt(Integer defaultValue){
try{
return scanner.nextInt()
}
catch(InputMismatchException e){
myStateObj.setErrorMessage("....");
return defaultValue;
}
}
}
Now you can use the class in this way :
MyCustomScanner scanner = new MyCustomScanner();
Integer intValue = scanner.nextInt();
Integer otherIntValue = scanner.nextInt(Integer.valueOf(4));

Run jar application from a springboot server

I am running a springboot server.
This server has some webservices.
One of those services has to run an external jar when it receives a request. Actually the server is the interface between a calculation engine (the jar), and the user.
There is the code :
public class Launcher extends Thread{
#Override
public void run() {
// TODO Auto-generated method stub
runJar(this.getJar(), this.getArgs());
}
private void runJar(String jar, String[] args){
try {
String[] s = new String[4+args.length];
s[0] = "nohup";
s[1] = "java";
s[2] = "-jar";
s[3] = jar;
for(int i = 0; i < args.length; i++){
s[i+4] = args[i];
}
Process p = Runtime.getRuntime().exec(s);
//Process exec = Runtime.getRuntime().exec(new String[] {"mkdir", "monTest"});
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println("failed");
e.printStackTrace();
}
}
}
public class Memory {
private ArrayList<Integer> startedIds;
public ArrayList<Integer> getStartedIds() {
return startedIds;
}
public void setStartedIds(ArrayList<Integer> startedIds) {
this.startedIds = startedIds;
}
public Memory() {
this.startedIds = new ArrayList<>();
}
public Memory(ArrayList<Integer> arr) {
this.startedIds = arr;
}
public int start() {
int id = this.findAvailableId();
this.getStartedIds().add(id);
System.out.println("i'm going to start with a big command!+uhpop");
String[] args = {"arg1","arg2", "arg3", "&"};
Launcher launcher = new Launcher("myJar.jar", args);
launcher.start();
return id;
}
private int findAvailableId() {
int id = 0;
while(this.getStartedIds().contains(id)){
id++;
}
return id;
}
}
If my jar do something really simple such as create a file, it works nice. But if it's more complex, the thread just stops working, the cpu fall to 0%. It depends on what i ask. For some task it can run 30-35seconds before the issue happens for others such as doing
while(true);
It stopped a few seconds latter.
I thought it was something like a timeout, but actually it is not a constant time. Maybe something like memory issue...?
I have tried to run the same code outside the springboot server (on a simple java project main that launch Memory.start() and it works well. So I supposed it was a spring boot misunderstanding from my side. If someone know how to make this jar run independently from the springboot server just tell me please.
Thank you.
I finally found the solution. I had to place a
p.waitFor();
so the thread launching the jar will not stop. Then, the input and the output of the jar are not connected to the input/output of the lauching thread, then, i had to create an other thread to monitor the output of the jar (it actually print it in the main thread). I found those informations here : http://labs.excilys.com/2012/06/26/runtime-exec-pour-les-nuls-et-processbuilder/
I still don't really understand why it was working outside the springboot server, actually it should not have run...
If somebody is interested, here is my code.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
class AfficheurFlux implements Runnable {
private final InputStream inputStream;
AfficheurFlux(InputStream inputStream) {
this.inputStream = inputStream;
}
private BufferedReader getBufferedReader(InputStream is) {
return new BufferedReader(new InputStreamReader(is));
}
#Override
public void run() {
BufferedReader br = getBufferedReader(inputStream);
String ligne = "";
try {
while ((ligne = br.readLine()) != null) {
System.out.println(ligne);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class Memory {
private ArrayList<Integer> startedIds;
public ArrayList<Integer> getStartedIds() {
return startedIds;
}
public void setStartedIds(ArrayList<Integer> startedIds) {
this.startedIds = startedIds;
}
public Memory() {
this.startedIds = new ArrayList<>();
}
public Memory(ArrayList<Integer> arr) {
this.startedIds = arr;
}
public int startJar() {
int id = this.findAvailableId();
this.getStartedIds().add(id);
System.out.println("i'm going to start with a big command!");
String[] args = {"arg1","arg2", "arg3"};
Launcher launcher = new Launcher("myJar.jar", args);
launcher.start();
return id;
}
private int findAvailableId() {
int id = 0;
while(this.getStartedIds().contains(id)){
id++;
}
return id;
}
public class Launcher extends Thread{
private String jar;
private String[] args;
public AntLauncher(String jar, String[] args) {
super();
this.jar = jar;
this.args = args;
}
#Override
public void run() {
runJar(this.getJar(), this.getArgs());
}
private void runJar(String jar, String[] args){
try {
String[] s = new String[3+args.length];
s[0] = "java";
s[1] = "-jar";
s[2] = jar;
for(int i = 0; i < args.length; i++){
s[i+3] = args[i];
}
Process p = Runtime.getRuntime().exec(s);
AfficheurFlux fluxSortie = new AfficheurFlux(p.getInputStream());
AfficheurFlux fluxErreur = new AfficheurFlux(p.getErrorStream());
new Thread(fluxSortie).start();
new Thread(fluxErreur).start();
p.waitFor();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Fin du programme");
}
}
}

How to capture Junit test case run result

I would like to call some methods on the basis of test case run result. My example code snippet is below
testrun ()
{
String Expected, Actual;
assertEquals(Expected, Actual);
}
So, in the above example, if the values of variables Expected and Actual are same, then the test case will pass, else it will fail.
I would like to capture the pass/fail and based upon it to perform some certain actions.
I am new to Junit and looking for some help here.
As answered here, you can use a TestWatcher, like this:
public class WatchTest {
#Rule
public TestRule watcher = new TestWatcher() {
#Override
protected void succeeded(Description description) {
System.out.println("Pass!");
}
#Override
protected void failed(Throwable e, Description description) {
System.out.println("Fail!");
}
};
#Test
public void testRun() throws Exception {
String expected = "asd";
String actual = "qwert";
assertEquals(expected, actual);
}
}
For TestNG (not for JUnit)
Add this code to your test class (see #AfterMethod annotation):
#AfterMethod
public void tearDown(ITestResult r) {
if(r.getStatus()==ITestResult.FAILURE) {
System.out.println(r.getMethod().getMethodName()+ " is failed");
// any more report action what you need
} else {
System.out.println(r.getMethod().getMethodName()+ " is OK");
// any more report action what you need
}
}
How to do it without JUnit/TestNG
You can wrap your test-body into try-catch and do something (call to TestRail etc.) before the test finished. Example (you can run it to see results in Output Panel, it's working):
public class SomeTest {
protected String methodName;
public void setMethodName(Class cl, Exception ex) {
methodName = cl.getName() + "." + ex.getStackTrace()[0].getMethodName() + "()";
}
public int half(Integer v) {
return v/2;
}
#Test
public void willFailed() throws Exception {
setMethodName(this.getClass(), new Exception());
try {
assertEquals(half(null), 2);
System.out.println("Report about good result in " + methodName);
// any more report action what you need
} catch(Exception ex) {
System.out.println("Report about bug in " + methodName); // Report before crash
// any more report action what you need
throw new Exception(ex); // booom
}
}
#Test
public void willPassed() throws Exception {
setMethodName(this.getClass(), new Exception());
try {
assertEquals(half(2), 1);
System.out.println("Report about good result in " + methodName);
// any more report action what you need
} catch(Exception ex) {
System.out.println("Report about bug in " + methodName); // Report before crash
// any more report action what you need
throw new Exception(ex); // booom
}
}
}

Instrumentation retransformation doesn't appear to be working

I'm just experimenting with Java Instrumentation because it's very interesting and I'd like to know more about it. I'm using it in conjunction with the javassist library to make bytecode manipulation much easier, and the "tools" library which is included in JDK install.
Here is my main class:
public class MainClass {
public static boolean first = true;
static{
AgentClass.initialize();
}
public static void loadAgent(){
String path = System.getProperty("user.dir") + "\\AgentJar.jar";
String nameOfRunningVM = ManagementFactory.getRuntimeMXBean().getName();
int p = nameOfRunningVM.indexOf('#');
String pid = nameOfRunningVM.substring(0, p);
try {
VirtualMachine vm = VirtualMachine.attach(pid);
vm.loadAgent(path, "");
vm.detach();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static void main(String[] args){
System.out.println("First run-through, code should be modified once.");
new Hello().hello();
first = false;
try {
AgentClass.getInstrumentation().retransformClasses(Class.forName("test.Hello"));
} catch (Exception e){
e.printStackTrace();
}
System.out.println("Second run-through, code should be modified twice.");
new Hello().hello();
}
}
Here is the "Hello" class:
public class Hello {
public void hello(){
System.out.println("Hello World!");
}
}
Here is the FileTransformer class:
public class FileTransformer implements ClassFileTransformer{
private static boolean first = true;
#Override
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
if (!className.contains("Hello"))
return null;
else{
byte[] result;
CtClass cc = null;
try {
cc = ClassPool.getDefault().get("test.Hello");
CtMethod method = cc.getDeclaredMethod("hello");
if (MainClass.first){
System.out.println("In transformer: first");
method.insertAfter("System.out.println(\"Modified First Time!\");");
}else{
System.out.println("In transformer: second");
method.insertAfter("System.out.println(\"I modified it again.!\");");
}
cc.writeFile();
result = cc.toBytecode();
} catch (Exception e) {
e.printStackTrace();
return null;
}
return result;
}
}
}
The agent class is in another jar, it's a basic implementation of it:
public class AgentClass {
protected static Instrumentation inst;
private static boolean added = false;
public static void agentmain(String args, Instrumentation inst){
AgentClass.inst = inst;
if (!added)
inst.addTransformer(new FileTransformer());
}
public static void premain(String args, Instrumentation inst){
AgentClass.inst = inst;
inst.addTransformer(new FileTransformer());
added = true;
}
public static void initialize(){
if (inst == null){
MainClass.loadAgent();
}
}
public static Instrumentation getInstrumentation(){
return inst;
}
}
When I run, I encounter no errors. However, the output is not how I would expect it to be.
Here is the output I get:
First run-through, code should be modified once.
In transformer: first
Hello World!
Modified First Time!
Second run-through, code should be modified twice.
Hello World!
Modified First Time!
You might notice that there is no line that reads "I modified it again!"
Any help is appreciated.
Not sure if there are any other issues here, but if you want to retransform classes, you need to register the ClassFileTransformer using the method that allows you to specify that the transformer can retransform. i.e.
if you call instrumentation.addTransformer(ClassFileTraIsformer), then you are stating that the transformer does not supports retransforms.
You need to call instrumentation.addTransformer(ClassFileTraIsformer, true) and this will make your transformer kick in.

Categories

Resources