I would like to get a list of test methods from the current test class before it is started. When I tried to extend TestListenerAdapter for this, testContext.getAllTestMethods() returned all test methods from all classes. But how to get only methods from the current class?
I found a partial answer on the question. First of all, I can get all test methods by extending TestListenerAdapter
public class MyListener extends TestListenerAdapter {
#Override
public void onStart(ITestContext testContext) {
super.onStart(testContext);
ITestNGMethod[] methods = testContext.getAllTestMethods();
// here we can save methods into some object
}
Then, in our test class in #BeforeClass() we can access the object and get the only methods from the this.getClass().getName() class. So, we filter the only methods from the current class. In this case we can access all required information like description and other important test attributes.
If you don't have a listener, you can also use the #BeforeClass annotation similar way as specified by OP's own answer:
#BeforeClass
public void setup(ITestContext context) {
for (ITestNGMethod method : context.getAllTestMethods()) {
if(method.getRealClass() == this.getClass()) {
// do what you have to do
}
}
}
Related
How can I cover the class instantiated inside a method and need to get the value that is not set.
Here is my Service class DemoClass.Java
public class DemoClass{
public void methodOne(){
ClassTwo classTwo=new ClassTwo();
classTwo.setName("abc");
customerRepo.save(classTwo);
ClassThree classThree=new ClassThree();
classThree.setId(classTwo.getId()); //here causing NullPointerException as ClassTwo is instantiated inside the method and the id value is not set and the test stops here.
classThree.setName("person1");
classThree.setUpdatedBy("person2");
}
}
As the classTwo is instantiated in the method level the test method does not get the getId(). And I can't change or add anything to the Controller class. The test stops at that line and causing NullPointerException as it doesn't know the value classtwo.getId() as it is not set. I need to cover that/ pass that line in the test class.
I tried mocking that class and spy also. Any Mockito solutions available for this.
The Id in ClassTwo is an autogenerated sequence number so no need of setting in DemoClass.Java
Here is my test class DemoClassTest.Java
#RunWith(MockitoJunitRunner.Silent.class)
public void DemoClassTest(){
#InjectMocks
DemoClass demoClass;
#Test
public void testMethodOne(){
demoClass.methodOne()
}
You could provide a customerRepo test double that just sets some specific id on classTwo:
public class TestCustomerRepo extends CustomerRepo {
public void save(ClassTwo classTwo) {
classTwo.setId(4711L);
}
}
But since you seem to be testing JPA code it would probably be a better idea to perform an integration test containing an actual database instead.
I usually do it like this:
long testId = 123;
Mockito.when(customerRepo.save(Mockito.any())).thenAnswer(invocation -> {
ClassTwo entity = (ClassTwo)invocation.getArgument(0);
entity.setId(testId);
return entity;
});
If you want to assert something on the ClassThree entity, do a Mockito.verify on the ClassThree repository mock.
I have a scenario in which I have to mock a method in parent class. The method is invoked from the method under test. I have not been able to mock the function using jMockit.
My super class is method is as follows
public abstract class SuperClass {
protected void emailRecipients(List<String> recipients) {
// Email recipients code. I want to mock this function.
}
}
My subclass is as follows
public class MyClass extends SuperClass {
public void methodUnderTest(HttpServletRequest request) {
// Some code here.
List<String> recipients = new ArrayList<>();
recipients.add("foo#example.com");
recipients.add("bar#example.com");
// This needs to be mocked.
this.emailRecipients(recipients);
}
}
I have tried using partial mocks using jMockit's tutorial, but it has not worked for me. My test method is given below.
UPDATE: I implemented Rogerio's suggestion as follows. The implementation still calls the real method. When I debug the instance of mocked class in Eclipse, this is what I see com.project.web.mvc.$Subclass_superClass#6b38c54e
#Test
public void testMethodUnderTest(#Mocked final SuperClass superClass) throws Exception {
final MyClass myClass = new MyClass();
new Expectations(myClass) {{
// .. Other expectations here
superClass.emailRecipients((List<String>) any);
}};
MockHttpServletRequest req = new MockHttpServletRequest();
myClass.methodUnderTest(req);
}
The issue is that when I try to mock the invocation of emailRecipients, it always tries to call the actual function. I am using Java 7, jMockit v1.35, and Maven 3x for our builds.
UPDATE The code is legacy code. As a result, we can't update it. We can not use PowerMock as it is not among the libraries that have been approved by the company. We can use either jMockit or Mockito or a combination of both.
The fact that you want to mock the method from parent class shows that your approach fails the Separation of Concerns/Single responsibility Pattern (SoC/SRP).
The use of PowerMock as suggested by Rajiv Kapoor is possible but this (as any use of PowerMock) would be a surrender to bad design.
You can solve your design problem by applying the Favor Composition over Inheritance principle (FCoI).
To do so you'd change your (most likely) abstract super class into a "normal" class. You'd create an interface that declares all the public and abstract methods in your super class. Your child class would no longer extend the parent class but implement the interface. It would get an instance of the former parent class as dependency and call it's methods providing common behavior as needed.
This dependency can easily mocked without the need of PowerMock.
UPDATE The code is legacy code. As a result, we can't update it.
In that case you are outruled.
The code you have is not unittestable because it is written in an untestable way. Your only chance is to write module and/or acceptance tests (without the use of a mocking framework) covering each and every execution path through your code.
This test will be expensive to create and slow but they will gurad your when refactoring the code to something testable (== changable) later.
see below example
P.S. use Mockito.any(HttpServletRequest.class)instead of Mockito.any(ArrayList.class) for your code
Super Class
public abstract class SuperClass {
protected void emailRecipients(List<String> recipients) {
System.out.println("Emailed!");
}
}
MyClass
public class MyClass extends SuperClass {
public void methodUnderTest() {
// Some code here.
ArrayList<String> recipients = new ArrayList<>();
recipients.add("foo#example.com");
recipients.add("bar#example.com");
// This needs to be mocked.
this.emailRecipients(recipients);
}
}
Test Class
public class TestCase {
MyClass myClass = Mockito.mock(MyClass.class, Mockito.CALLS_REAL_METHODS);
#Before
public void prepare() {
PowerMockito.doNothing().when(myClass).emailRecipients(Mockito.any(ArrayList.class));
/*PowerMockito.doAnswer(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
System.out.println("Custom code");
return null;
}
}).when(myClass).emailRecipients(Mockito.any(ArrayList.class));*/
}
#Test
public void testMethodUnderTest() throws Exception {
myClass.methodUnderTest();
}
}
If you don't want the code in emailRecipients to execute then use doNothing()
else use doAnswer to execute some other code
I'm running through some service tests and I am testing a concrete class that extends from one that uses generics.
An example setup of the service layer is below:
public abstract class AbstractService <E extends AbstractEntity, IT extends AbstractItem> {
public void deleteAllItems(E entity) {
List<IT> items = new ArrayList<IT>(entity.getItems());
for(IT item : items) {
//Yada, yada
}
}
}
public class Service extends AbstractService<Entity, Item> {
}
public class OtherService() {
#Inject
private ServiceManager serviceManager;
public void deleteItems(Entity e) {
serviceManager.getService().deleteAllItems(e);
}
}
Then to test it I have the following:
public class Test {
private Service service;
private OtherService otherService;
private ServiceManager serviceManager;
#BeforeMethod
public void setup() {
serviceManager= mock(serviceManager.class);
service= mock(Service.class);
when(serviceManager.getService()).thenReturn(service);
otherService=injector.getInstance(OtherService.class);
}
#Test
public void test() {
Entity e = new Entity();
//Attach some items
otherService.deleteItems(e);
verify(service).deleteAllItems(e);
}
}
This should call the OtherService, which exists (We're using injection to get ahold of the object), and then call the method deleteItems(), which in turn should call deleteAllItems() on the Service. Before I had implemented the Java generics, this worked fine, but since I have implemented the Java generics, the Mockito test fails with the following exception:
java.lang.NoSuchMethodError:
Service.deleteAllItems(Entity;)V
at
Test.test(Test.java:XXX)
org.mockito.exceptions.misusing.UnfinishedVerificationException:
Missing method call for verify(mock) here:
-> at Test.test(Test.java:XXX)
Example of correct verification:
verify(mock).doSomething()
Also, this error might show up because you verify either of:
final/private/equals()/hashCode() methods. Those methods cannot be
stubbed/verified.
Which sounds like it can't find the method. Should I instead mock the abstract class of AbstractService or is there something else that I am missing?
EDIT
From what I've seen of the Mockito inner workings, it creates an instance of this:
public void AbstractService.deleteAllItems(Entity)
For the MockitoMethod object, so that would make sense that Service.deleteAllItems() "isn't called", it appears Mockito assumes only the baseclass was ever called. So it does appear that I need to mock the base class instead. I'm going to investigate further, but if anyone has any other ideas, I'm open to suggestions
I can suggest to localize the problem - either it is in mocking:
#Test
public void test() {
Entity e = new Entity();
service.deleteItems(e); // Note! 'service' itself, not an 'otherService'
verify(service).deleteAllItems(e);
}
or in injection (remove inheritance and generics):
public class Service /*extends AbstractService<Entity, Item>*/ {
public void deleteAllItems(Entity entity) {
//...
}
}
Split the problem iterativelly and you will find the cause.
When you create a non-generic subclass of a generic class, Java creates "bridge methods" for any methods that use the generic type. The bridge methods look like the inherited methods but use the the specific class specified for the generic parameters instead of generics.
Java creates these methods because the methods of the subclass are not generic, so they need to "look like" non-generic methods (i.e. not subject to erasure, reflection will work as expected, etc). See this answer for details.
The solution is to have Mockito mock the type returned by serviceManager.getService().
After further investigation, I found a way to force Mockito to call the correct class. As I mentioned briefly, we're using injection to get ahold of the object. During the setup we do run through a setup of the injector, which I hadn't felt was causing the issue. But it did present a solution. This was how we were calling it:
Injector injector = Guice.createInjector(new Module() {
#Override
public void configure(Binder binder) {
service = mock(Service.class);
binder.bind(Service.class).
toInstance(service);
}
To solve the issue, we just bound the AbstractService class to the mocked instance of the Service class, like so:
Injector injector = Guice.createInjector(new Module() {
#Override
public void configure(Binder binder) {
service = mock(Service.class);
binder.bind(Service.class).
toInstance(service);
binder.bind(AbstractService.class).
toInstance(service);
}
So now, when Mockito attempts to get an instance of the AbstractService, it calls the mocked Service and solves our issue.
If anyone has any feedback it there is an alternative solution, then feel free to post and I can test it out and check if there are better methods that what we are doing.
I defined some classes with, each one, several public methods with #Test annotation. All methods follow the same behavioral pattern (retrieve ressources from IDs, test if empty, log, call the real test for each line on the resource). So, I've externalized this behavior in an abstract class I instanciate on each method, like this:
#Test
public void someTest(){
new BasicTestPattern("X","Y","Z"){ // some parameters to retrieve resources
#Override
protected void testLine(){
someCheck1();
someCheck2();
}
}.run();
}
This solution eliminate 10-30 lines per test method.
Now, I want to go further with a custom annotation, like that:
#TestPattern(param1="X",param2="Y",param3="Z")
public void someTest(){
someCheck1();
someCheck2();
}
Finally I created a little framework to retrieve all the methods with this new annotation in order to instanciate BasicTestPattern and execute it. It is executed well in a TestCase subclass, like that:
TestCase junit_test = new TestCase(){
#Override
public void runTest() {
pattern.run();
}
};
junit_test.run();
However, no Test is displayed/listed in the JUnit view from Eclipse. I see only the number of tests succeeded.
How can I do that ? Thank you.
You probably will need to make your own custom Runner to find all the methods annotated with your #TestPattern method. (and probably also with #Test ?)
Then your test class will look like this:
#RunWith(YourRunner.class)
public class YourTest{
#TestPattern(param1="X",param2="Y",param3="Z")
public void someTest(){
...
}
#Test
public void anotherNormalTest(){
...
}
}
This Blog explains how to write custom Runners. But you can probably get away with extending BlockJUnit4ClassRunner to add the your special test methods to the list of tests to run.
I think you would only have to override the computeTestMethods() method which is how BlockJUnit4ClassRunner finds all the test methods to run (the methods annotated with #Test) you can override it to find the methods you annotated with your own annotation.
public class your TestRunner extends BlockJUnit4ClassRunner{
protected List<FrameworkMethod> computeTestMethods() {
//this is all the #Test annotated methods
List<FrameworkMethod> testAnnotatedMethods = super.computeTestMethods();
//these are all the methods with your #TestPattern annotation
List<FrameworkMethod> yourAnnotatedMethods = getTestClass().getAnnotatedMethods(TestPattern.class);
//do whatever you need to do to generate the test
//methods with the correct parameters based on
//the annotation ?
//Might need to make fake or
//synthetic FrameworkMethod instances?
...
//combine everyting into a single List
List<FrameworkMethod> allTestMethods =...
//finally return all the FrameworkMethods as a single list
return allTestMethods;
}
}
You might have to make your own FrameworkMethod implementation wrapper to get the info from the annotation and do whatever set up is required before invoking the method.
This will make it seamlessly integrate with normal JUnit classes and work with the JUnit IDE view
Good Luck
I have two classes:
public abstract class AbstractFoobar { ... }
and
public class ConcreteFoobar extends AbstractFoobar { ... }
I have corresponding test classes for these two classes:
public class AbstractFoobarTest { ... }
and
public class ConcreteFoobarTest extends AbstractFoobarTest { ... }
When I run ConcreteFoobarTest (in JUnit), the annotated #Test methods in AbstractFoobarTest get run along with those declared directly on ConcreteFoobarTest because they are inherited.
Is there anyway to skip them?
Update: Misunderstood the Question
Make AbstractFoobarTest abstract.
That way the test methods in
AbstractFoobarTest are only run
once, when ConcreteFoobarTest is
executed. You are going to need a
concrete subclass to test the
methods in AbstractFoobar anyway.
Or just remove the inheritance
between AbstractFoobartest and
ConcreteFoobarTest. You don't want
to make use of it anyway.
You really don't need AbstractFoobarTest in the first place because after all you can't create an instance of the abstract class, so, you will still rely on your concrete class to test your abstract class.
That means, you will end up using your ConcreteFoobarTest will test the APIs from the abstract class. Thus, you will have just this:-
public class ConcreteFoobarTest { ...
#Test
public void testOne() {
ConcreteFoobar cf = new ConcreteFoobar();
// assert cf.conreteAPI();
}
#Test
public void testTwo() {
ConcreteFoobar cf = new ConcreteFoobar();
// assert cf.abstractClassAPI();
}
}
Using process tags would allow you to run into specific bodies of code