How does all annotations work in TestNg without main() method - java

I have a doubt in TestNG with Java. I am completly new to TestNG. My doubt is, How all the test cases are executing using TestNG in java without having main() method? Please suggest me if you have any ideas. Following code is the example of a sample test case using TestNG in java. But if you notice, you can find one thing that there is no main() method in the code. Then, how does the testcases are executing?
I have another doubt. Is main() method needed for selenium Webdriver and TestNG combination to execute a script? Or can we execute testcases without main() method? If we can execute testcases without main(), then how does it is possible?
package com.first.example;
import org.testng.annotations.Test;
public class demoOne {
#Test
public void firstTestCase()
{
System.out.println("im in first test case from demoOne Class");
}
#Test
public void secondTestCase()
{
System.out.println("im in second test case from demoOne Class");
}
}

This is a valid doubt many testers have. Because the main() method is needed to run the Java program and while writing tests in TestNg we don't use main() method, and we use Annotations instead.
Annotations in TestNG are lines of code that can control how the method below them will be executed. So, in short you don't need to write main() method, TestNg do that by itself. Refer the code at the end in Annotations documentation to get the idea how it happens.
As rightly pointed out in this answer: https://stackoverflow.com/a/1918154/3619412
Annotations are meta-meta-objects which can be used to describe other
meta-objects. Meta-objects are classes, fields and methods. Asking an
object for its meta-object (e.g. anObj.getClass() ) is called
introspection. The introspection can go further and we can ask a
meta-object what are its annotations (e.g. aClass.getAnnotations).
Introspection and annotations belong to what is called reflection and
meta-programming.
Also, it's not necessary to have main() method in your tests, but you can use main() method to run the TestNg tests if you want. Refer this.

to run script from cmd prompt we use below statement,
java org.testng.TestNG testng1.xml
main method in TestNG.java class how accept the command line argument,
public static void main(String[] argv) {
TestNG testng = privateMain(argv, null);
System.exit(testng.getStatus());
}

You saw it right. Test-cases get executed through testng, the testing framework which was inspired from junit without having the main() method but extensively uses annotations.
Annotations
As per the documentation in Annotations majority of the APIs require a huge amount of boilerplate code. To write a web service you need to provide a paired interface and implementation. This boilerplate could be automatically generated by a tool if the program can be decorated with annotations indicating which methods were remotely accessible. Annotations doesn't affects the program semantics directly but they do affect the way programs are treated by tools and libraries, which can in turn affect the semantics of the running program.
TestNG
TestNG is a simple annotation-based test framework which uses a marker annotation type to indicate that a method is a test method and should be run by the testing tool. As an example:
import org.testng.annotations.Test;
#Test
public void foo() {
System.out.println("With in foo test");
}
The testing tool which is being used is as follows:
import java.lang.reflect.*;
public class RunTests {
public static void main(String[] args) throws Exception {
int passed = 0, failed = 0;
for (Method m : Class.forName(args[0]).getMethods()) {
if (m.isAnnotationPresent(Test.class)) {
try {
m.invoke(null);
passed++;
} catch (Throwable ex) {
System.out.printf("Test %s failed: %s %n", m, ex.getCause());
failed++;
}
}
}
System.out.printf("Passed: %d, Failed %d%n", passed, failed);
}
}

Related

How do you unit test main method in Java?

This is my class with main function. Here I initialize a spring bean which has camel route in it. I do not want to test any other classes being referred in this code but I just want to increate code coverage of this main class. How do I mock and test this class?
import org.apache.camel.main.Main;
public class ABC{
public static void main(String[] args) {
Main main = new Main();
MyCamelRoute myCamelRoute = SpringUtil.getBean(MyCamelRoute.class);
main.addRouteBuilder(myCamelRoute);
Thread t = new Thread(() -> {
try {
main.run();
} catch (Exception e) {
_logger.error("Unable to add route", e);
}
}, "started route");
t.start();
}
}
As you're writing of "mocks" I assume you intend to write a unit test.
ONE: Either you test a class or you mock it. You use mocks to make your test independent of the behaviour (and thus possible bugs) of other units (the "dependencies" of your "system under test" (SUT)).
TWO: You do not write tests to increase code coverage. You write tests to enforce requirements of the API contract.
THREE: To test your main method: call it! You can put in arguments and see if the return value matches your expectations.
FOUR: The problem here might be that you've got static dependencies you cannot control. Spring allows you to configure mocks for bean injection. Can't tell you details right now but I am sure you can find out, it should be something like #Configuration annotated classes or test specific versions of them.
But: your test has no control whatsoever over the main object. And sincerely, I would guess that actually you intend to test the Mainclass. Also you might want to inject the Main instance via Spring means.
FIVE: I am not sure wether it is a good idea to involve multi threading in unit tests as it means your test cannot control the environment of your sut. If you do not know where your test starts, you cannot decide if where it ends up is correct or not.

JUnit without inversion of control

Currently the JUnit5 Framework works with Inversion of Control. I.e. you annotate a test method with #Test and then JUnit scans your classpath (in the simplest case)
Now is there a way for me to be in charge of calling the test cases through JUnit APIs? Maybe by hooking my test implementations to some test registry provided by JUnit?
I'm pretty new to JUnit - how did older versions go about this?
The reason I'm asking is that normally to execute my test cases, I'd have to run something along the lines of
java -jar junit-platform-standalone.jar --class-path target --scan-class-path
on the command line. My situation requires me to run the test cases through by executing one of my own classes, like that e.g.
java /com/example/MyTestCassesLauncher
EDIT: to clarify, I need one of my own classes to be hosting/launching my test cases, something like this:
// Maybe this needs to extend one of JUnit's launchers?
public class MyTestCassesLauncher {
public static void main(String[] args) {
JUnitLauncher.launchTests(new MyTestClass());
}
}
where JUnitLauncher.launchTests is some kind of API provided by the platform. I'm not looking for a method with that exact same signature but a mechanism that would allow me to ultimately call my own MyTestClassesLauncher class to run the tests.
Thanks in advance.
Not sure what you arÄ™ actually trying to achieve but in Junit5 to change behaviour of your tests you can use Extensions mechanism, similar to Junit4 RunWith but more powerful
Such custom extension can provide some additional logic like in this logging example
public class LoggingExtension implements
TestInstancePostProcessor {
#Override
public void postProcessTestInstance(Object testInstance,
ExtensionContext context) throws Exception {
Logger logger = LogManager.getLogger(testInstance.getClass());
testInstance.getClass()
.getMethod("setLogger", Logger.class)
.invoke(testInstance, logger);
}
}
The way Junit controls it's flow is Junit problem - you should not modify framework but extend it

Adding custom messages to TestNG failures

I'm in the process of migrating a test framework from JUnit to TestNG. This framework is used to perform large end-to-end integration tests with Selenium that take several minutes to run and consist of several hundred steps across dozens of browser pages.
DISCLAIMER: I understand that this makes unit testing idealists very uneasy, but this sort of testing is required at most large service oriented companies and using unit testing tools to manage these integration tests is currently the most widespread solution. It wasn't my decision. It's what I've been asked to work on and I'm attempting to make the best of it.
At any rate, these tests fail very frequently (surprise) and making them easy to debug is of high importance. For this reason we like to detect test failures before they're reported, append some information about the failure, and then allow JUnit to fail with this extra information. For instance, without this information a failure may look like:
java.lang.<'SomeObscureException'>: <'Some obscure message'> at <'StackTrace'>
But with the added information it will look like:
java.lang.AssertionError:
Reproduction Seed: <'Random number used to generate test case'>
Country: <'Country for which test was set to run'>
Language: <'Localized language used by test'>
Step: <'Test step where the exception occurred'>
Exception Message: <'Message explaining probable cause of failure'>
Associated Exception Type: <'SomeObscureException'>
Associated Exception Message: <'Some obscure message'>
Associated Exception StackTrace: <'StackTrace'>
Exception StackTrace: <'StackTrace where we appended this information'>
It's important to note that we add this information before the test actually fails. Because our reporting tool is based entirely on the exceptions thrown by JUnit this ensures that the information we need is present in those exceptions. Ideally I'd like to add this information to an HTML or XML document using a reporter class after the test fails but before teardown is performed and then modify our reporting tool to pick up this extra information and append it to our e-mail reports. However, this has been a hard sell at our sprint planning meetings and I have not been allotted any time to work on it (running endless regressions for the developers is given higher priority than working on the test framework itself. Such is the life of the modern SDET). I also believe strongly in balance and refuse to cut into other parts of my life to get this done outside of tracked time.
What we're currently doing is this:
public class SomeTests extends TestBase {
#Test
public void someTest() {
// Test code
}
// More tests
}
public abstract class TestBase {
#Rule
public MyWatcher watcher = new MyWatcher();
// More rules and variables
#Before
public final void setup() {
// Read config, generate test data, create Selenium WebDriver, etc.
// Send references to all test objects to MyWatcher
}
}
public class MyWatcher extends TestWatcher {
// Test object references
#Override
public void failed(Throwable throwable, Description description) {
StringBuilder sb = new StringBuilder();
// Append custom test information to sb.
String exceptionSummary = sb.toString();
Assert.fail(exceptionSummary);
}
#Override
public void finished(Description description) {
// Shut down Selenium WebDriver, kill proxy server, etc.
}
// Miscellaneous teardown and logging methods
}
JUnit starts.
SomeTests inherits from TestBase class. TestBase instantiates our own instance of a TestWatcher via #Rule annotation (MyWatcher).
Test setup is run in TestBase class.
References to test objects are sent to MyWatcher.
JUnit begins someTest() method.
someTest fails at some point.
JUnit calls overridden failed() method in MyWatcher.
failed() method appends custom test information to new message using references passed by TestBase.
failed() method calls JUnit's Assert.fail() method with the customized message.
JUnit throws a java.lang.Assertion error for this new failure with the customized message. This is the exception that actually gets recorded in the test results.
JUnit calls overridden finished() method.
finished() method performs test teardown.
Our reporting tool picks up the summarized errors thrown by JUnit, and includes them in the e-mails we receive. This makes life easier than debugging the original exceptions would be without any of the extra information added by MyWatcher after the original failure.
I'd now like to implement a similar mechanism using TestNG. I first tried adding an IInvokedMethodListener in a #Listener annotation to our TestBase class as a way of replacing the TestWatcher that we were using in JUnit. Unfortunately the methods in this listener were getting called after every #BeforeMethod and #AfterMethod call as well as for the actual tests. This was causing quite a mess when I called Assert.fail from inside the IInvokedMethodListener so I opted to scrap this approach and insert the code directly into an #AfterMethod call in our TestBase class.
Unfortunately TestNG does not appear to handle the 'failing twice' approach that we were using in JUnit. When I call Assert.fail in the #AfterMethod of a test that has already failed it gets reported as an additional failure. It seems like we're going to have to come up with another way of doing this until I can get authorization to write a proper test reporter that includes the information we need for debugging.
In the meantime, we still need to dress up the exceptions that get thrown by TestNG so that the debugging information will appear in our e-mail reports. One idea I have for doing this is to wrap every single test in a try/catch block. If the test fails (an exception gets thrown), then we can catch that exception, dress it up in a summary exception with the debugging information added to that exception's message, and call Assert.fail with our new summarized exception. That way TestNG only ever sees that one exception and should only report one failure. This feels like a kludge on top of a kludge though, and I can't help but feel that there's a better way of doing this.
Does anybody know of a better method for modifying what gets reported by TestNG? Is there some kind of trick I can use for replacing the original exception with my own using ITestContext or ITestResult? Can I dive in somewhere and remove the original failure from some list, or is it already too late to stop TestNG's internal reporting by the time I get to the #AfterMethod functions?
Do you have any other advice regarding this sort of testing or exception handling in general? I don't have many knowledgeable co-workers to help with this stuff so I'm pretty much just winging it.
Implement IInvokedMethodListener:
public class InvokedMethodListener implements IInvokedMethodListener {
#Override
public void beforeInvocation(IInvokedMethod method, ITestResult testResult) {
}
#Override
public void afterInvocation(IInvokedMethod method, ITestResult result) {
if (method.isTestMethod() && ITestResult.FAILURE == result.getStatus()) {
Throwable throwable = result.getThrowable();
String originalMessage = throwable.getMessage();
String newMessage = originalMessage + "\nReproduction Seed: ...\nCountry: ...";
try {
FieldUtils.writeField(throwable, "detailMessage", newMessage, true);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Register it in your test:
#Listeners(InvokedMethodListener.class)
public class YourTest {
#Test
public void test() {
Assert.fail("some message");
}
}
or in testng.xml.
If you execute it, you should get:
java.lang.AssertionError: some message
Reproduction Seed: ...
Country: ...
You can user SoftAssert Class in testNG for implementing above scenario. SoftAssert Class has an hash map array which stores all the error message from Asserts in test cases and prints them in the end of the test case. you can also extend Assertion class to implement methods as per your requirement.
More information regarding SoftAssert class and its implementation can be found here

How can I make JUnit 4.8 run code after a failed test, but before any #After methods?

I'm driving a suite of Selenium tests (actually WebDriver-backed Selenium) using JUnit 4.8.2. I'd like the tests to automatically take a screenshot of the browser as soon as the test fails an assertion. All the tests inherit from SeleniumBaseTestCase, and the majority then further inherit from from SeleniumBastTestCaseWithCompany (which uses #Before and #After methods to create and then clean up common test data via Selenium).
I've tried adding a subclass of TestWatchman as a #Rule in SeleniumBaseTestCase, overriding TestWatchman's failed method to take the screenshot. The trouble is that the #After methods cleaning up the test data are being run before TestWatchman's failed method is called, so the screenshots are all of the final step of the clean-up, not the test that failed.
Looking into it a little, it seems that TestWatchman's apply method just calls the passed Statement's evaluate method (the only exposed method), which calls the #After methods, leaving TestWatchman (or any other Rule) no chance to insert any code between the execution of the test and of the #After methods, as far as I can tell.
I've also seen approaches that create a custom Runner to alter the Statements created so that methods annotated with the custom #AfterFailure are run before #After methods (so the screenshot can be taken in such an #AfterFailure method), but this relies on overriding BlockJUnit4ClassRunner's withAfters method, which is deprecated and due to become private, according to the documentation, which suggests using Rules instead.
I've found another answer on SO about the #Rule lifecycle that makes it sound like this simply might not be possible in JUnit 4.8, but may be possible in JUnit 4.10. If that's correct then fair enough, I'd just like confirmation of that first.
Any thoughts on an elegant and future-proof way in which I can achieve what I want would be much appreciated!
You are right in your analysis, #Befores and #Afters are added to the list of Statements before any Rules. The #Before gets executed after the #Rule and the #After gets executed before the #Rule. How you fix this depends on how flexible you can be with SeleniumBaseTestCaseWithCompany.
The easiest way would be to remove your #Before/#After methods and replace them with an ExternalResource. This could look something like:
public class BeforeAfterTest {
#Rule public TestRule rule = new ExternalResource() {
protected void before() throws Throwable { System.out.println("externalResource before"); }
protected void after() { System.out.println("externalResource after"); }
};
#Test public void testHere() { System.out.println("testHere"); }
}
this gives:
externalResource before
testHere
externalResource after
This field can be put into your base class, so it gets inherited/overridden. Your problem with ordering between #After and your rules then goes away, because you can order your rules how you like, using #RuleChain (in 4.10, not 4.8).
If you can't change SeleniumBaseTestCaseWithCompany, then you can extend BlockJUnit4ClassRunner, but don't override withAfters, but override BlockJUnit4ClassRunner#methodBlock(). You can then call super.methodBlock, and reorder the Statements as necessary[*].
[*]You could just copy the code, and reorder the lines, but withRules is private and therefore not callable from a subclass.

Selenium, minimizing repetitious code

The selenium tests I'm gonna be doing are basically based on three main steps, with different parameters. These parameters are passed in from a text file to the test. this allows easy completion of a test such as create three of "X" without writing the code to do the create three times in one test.
Imagine i have a test involving creating two of "X" and one of "Y". CreateX and CreateY are already defined in separate tests. Is there a nice way of calling the code contained in createX and createY from say, Test1?
I tried creating a class with the creates as seperate methods, but got errors on all the selenium.-anything-, ie every damn line. it goes away if i extend seleneseTestCase, but it seems that my other test classes wont import from a class that extends seleneseTestCase. I'm probably doing something idiotic but i might as well ask!
EDIT:
well for example, its gonna be the same setUp method for every test, so id like to only write that once... instead of a few hundred times...
public void ready() throws Exception
{
selenium = new DefaultSelenium("localhost", 4444, "*chrome", "https://localhost:9443/");
selenium.start();
selenium.setSpeed("1000");
selenium.setTimeout("999999");
selenium.windowMaximize();
}
thats gonna be used EVERYWHERE.
its in a class called reuseable. Id like to just call reuseable.ready(); from the tests SetUp... but it wont let me....
public class ExampleTest {
#Before
public void setup() {
System.out.println("setup");
}
public void someSharedFunction() {
System.out.println("shared function");
}
#Test
public void test1() {
System.out.println("test1");
someSharedFunction();
}
#Test
public void test2() {
System.out.println("test2");
someSharedFunction();
}
}
The contents of the function after the #Before annotation is what will be executed before every test. someSharedFunction() is an example of a 'reusable' function. The code above will output the following:
setup
test1
shared function
setup
test2
shared function
I would recommend using JUnit and trying out some of the tutorials on junit.org. The problem you have described can be fixed using the #Before annotation on a method that performs this setup in a super class of your tests

Categories

Resources