How to run jul-to-slf4j bridge once per JVM? - junit

I'd like to run Surefire in parallel mode (multiple JVMs) where each JVM must run:
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
exactly once before the first test. How can this be done?

There are various ways to make some code run at the beginning of a test suite.
Here are 4 (I'm sure there are more):
JUnit via RunWith Suite with Suite.SuiteClasses and BeforeClass (adapted from examples in SuiteTest):
#RunWith(Suite.class)
#SuiteClasses({FirstTest.class, SecondTest.class/*, ...*/, LastTest.class})
public static class AllWithSLF4JBridgeHandler {
#BeforeClass
public static void registerRootLoggerHandlers() {
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
}
}
TestNG with BeforeSuite:
/**
* Base class for each test class (i.e. every test class should extend this class).
*/
public abstract class BaseTest {
#BeforeSuite
public void registerRootLoggerHandlers() {
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
}
}
TestNG with Guice:
/**
* Test module. Each test class should be annotated with `#Guice(TestModule.class)`.
*/
public class TestModule implements Module {
#Override
public void configure(Binder binder) {
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
}
}
Static initialization blocks (test-framework independent):
/**
* Base class for each test class (i.e. every test class should extend this class).
*/
public abstract class BaseTest {
static {
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
}
}
I'm not sure how all of these methods work with Surefire's parallel mode. Methods 1 and 2 may not work there but I believe methods 3 and 4 should.
Another option would be to not use the programmatic installation of the SLF4JBridgeHandler but to use a java.util.logging.config file or class (see LogManager):
"java.util.logging.config.file":
logging.properties file:
// register SLF4JBridgeHandler as handler for the j.u.l. root logger
handlers = org.slf4j.bridge.SLF4JBridgeHandler
System property assignment:
java -Djava.util.logging.config.file=/path/to/logging.properties ...
This works well if you know the path to your logging file beforehand.
"java.util.logging.config.class":
Using a file may not be a good option if you're deploying a WAR and don't know where the file will be, etc. so alternatively you can create a logging config class:
public class SLF4JBridgeHandlerInitializer {
public SLF4JBridgeHandlerInitializer() throws IOException {
String loggingConfigurationString = "handlers = " + SLF4JBridgeHandler.class.getName();
InputStream inputStream = new ByteArrayInputStream(loggingConfigurationString.getBytes());
LogManager.getLogManager().readConfiguration(inputStream);
}
}
System property assignment:
java -Djava.util.logging.config.class=package.SLF4JBridgeHandlerInitializer ...
I've done this before and it has worked well for me (SLF4JBridgeHandler.Initializer by mfulton26 · Pull Request #57 · qos-ch/slf4j).
These final two options should initialize each JVM instance as long as the appropriate system property is set.

Related

Unable to Mock functions inside static method Powermock

I am writing unit test for the below code using junit and mockito
public class Abc implements Runnable
{
private static ServerSocket server;
private static int port;
public Abc(int cPort)
{
port = cPort;
}
public void run()
{
init();
}
public static void init()
{
try {
server = new ServerSocket(port);
...something...
client.close();
}
}
catch(IOException e)
{
System.out.println("Exception inside init()...");
e.printStackTrace();
}
}
};
Unit test I have written
#RunWith(PowerMockRunner.class)
#PrepareForTest({ServerSocket.class})
public class abcTest {
#Mock (name = "server") //same name as private var.
ServerSocket mockServer;
#InjectMocks
Abc abc;
#Test
public void testInit() throws Exception {
int port = 1880;
Socket mockClient = Mockito.mock(Socket.class);
PowerMockito.whenNew(ServerSocket.class).
withArguments(anyInt()).thenReturn(mockServer);
abc = new Abc(port);
Abc.init();
PowerMockito.verifyNew(ServerSocket.class).withArguments(port);
}
};
But the call always go to original function definition. I am using junit 4.11 with mockito 2.28.2 and powermockito 2.0.2. I'm using java after a long time. Now its feel like kind of new. Please correct me if anything wrong in the code also.
You will need to change your PrepareForTest annotation
to #PrepareForTest({Abc.class}).
From the PowerMockito docu:
This annotation tells PowerMock to prepare certain classes for testing. Classes needed to be defined using this annotation are typically those that needs to be byte-code manipulated
In this case that refers to the class which creates the new instance of ServerSocket. ServerSocket itself is a non-final public class that does not require special handling from PowerMockito (instead Mockito can deal with this class on its own).
You could also change your test to do the following:
#Test
public void testInit() throws Exception {
int port = 1880;
ServerSocket mockServer = Mockito.mock(ServerSocket.class);
PowerMockito.whenNew(ServerSocket.class)
.withArguments(Mockito.anyInt()).thenReturn(mockServer);
Abc.port = port;
Abc.init();
PowerMockito.verifyNew(ServerSocket.class).withArguments(port);
}
(This first point is unrelated to whether the test fails or succeeds)
I do not know why you mix object's and static method behaviour together, but I think you should change that.In the test instead of creatic an ABC object, just could just set the static port variable directly.
Or alternatively change the whole ABC class into an object.
#InjectMocks failed for me as there is no default constructor
(Actually I got an error message in the console when trying to execute your code)
Additonaly you create a new instance of ABC in your test, which would have overwritten the things done by the annotations. Also as server is created during the init call, there is no need to inject a mock for it.
powermockito 2.0.2 actually depends on junit 4.12, so I am not sure what effects downgrading to an older version might have.
Socket mockClient seemed somewhat unrelated to the code your posted, so I removed it from my example in the answer, however as you use a client (I assume that is your Socket) in your code your probably need to do some mocking for that as well and provide the mock to the method accordingly.

How to access protected method of Java jar file's class

I am using a Java command-line application (which is open-source) as a jar file for my jrubyonrails project. The main application is like following
public class Decoder extends Annotator {
public Decoder() {
super();
}
public static void main(String[] args) {
... // Do something that I don't want
myDesiredMethod();
... // And some other thing
}
...
}
There are many steps which I want to skip, I only want myDesiredMethod function. And it is a protected method from the parent Annotator class.
public class Annotator extends Helper {
...
protected SomeClass myDesiredMethod(boolean reMap) throws Exception { ... }
...
}
Annotator class does not have any public constructor so that I cannot:
ann = Annotator.new
It raises this error: TypeError: no public constructors for Annotator.
Then I try to implement another class which inherits Annotator in order to access myDesiredMethod. This is the jruby code I have tried so far
require 'java'
require 'decoder.jar'
java_import java.util.ArrayList
java_import java.lang.StringBuilder
module MyModule
class RuDecoder < Annotator
include_package 'com.decoder'
def self.my_method
myDesiredMethod
end
end
It returns the error: NoMethodError: undefined method 'myDesiredMethod' for MyModule::RuDecoder:Class. Seems jruby does not look for the method of the parent class.
Is there any solution in my case, I don't want to rebuild the java library to jar and manually put it into my program every time it has an update.
Turns out that I made thing over-complicated. I can call the default constructor of Annotator as following:
constructors = Annotator.java_class.declared_constructors.first
constructors.accessible = true
annotator = constructors.new_instance.to_java
And use simple call myDesiredMethod: annotator.myDesiredMethod

Is it possible to name a test suite in JUnit 4?

In JUnit3, one would could name a test suite like this:
public static Test suite() {
TestSuite suite = new TestSuite("Some test collection");
suite.addTestSuite(TestX.class);
return suite;
}
Is there an equivalent way to do this in JUnit4?
Thanks.
EDIT
Thank you, I actually managed to get it working. My question was if there is a JUnit4 equivalent way of specifying the name/description of a test suite, like in JUnit3 with "Some test collection".
Some background:
I'm converting junit tests in legacy code to the version 4, and I don't want to lose any information if possible. I apologize, I should really have been more specific in the original question.
You can do this with the Suite runner #RunWith(Suite.class):
#RunWith(Suite.class)
#SuiteClasses({Test1.class, Test2.class, TestX.class})
public class MySuite {}
Where Test1, Test2, TestX contain your tests
ref. RunWith, Suite
update:
WRT changing the actual description of your suite, I don't think there's a way to do it out-of-the-box (if there is I haven't seen it yet). What you can do, is to define your own runner with a custom description [update2]:
#RunWith(DescribedSuiteRunner.class)
#SuiteClasses({Test1.class, Test2.class, TestX.class})
#SuiteDescription("Some test collection")
public class MySuite {}
public class DescribedSuiteRunner extends Suite {
// forward to Suite
public DescribedSuiteRunner(Class<?> klass, RunnerBuilder builder)
throws InitializationError {
super(klass, builder);
}
#Override
protected String getName() {
return getTestClass()
.getJavaClass()
.getAnnotation(SuiteDescription.class)
.value();
}
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface SuiteDescription {
String value();
}
The default implementation of getName just returns the class being tested's name
Yes, In JUnit 3.x, the JUnit methods had to be specifically named. They needed to begin with the word test in order for JUnit to run that as a test case. Now you can just use the #Test annotation:
#Test
public void thisIsMyTest() {
// test goes here
}
Also in JUnit4 you can state if you want some tests to run before or after all the tests in this class are invoked:
#Before
public void init() throws Exception {
System.out.println("Initializing...");
}
#After
public void finish() throws Exception {
System.out.println("Finishing...");
}
Further comparisons between JUnit3 and JUnit4 here and here.
Edit: after blgt's comment, I see I might have misunderstood your intent.
You are probably looking for #RunWith(Suite.class) - When a class is annotated with #RunWith, JUnit will invoke the class in which is annotated so as to run the tests, instead of using the runner built into JUnit. Full example of usage is here, tl;dr below:
#RunWith(Suite.class)
#SuiteClasses({ FirstTest.class, SecondTest.class })
public class AllTests {
...
}

Accessing non public Method of Object in JUNIT

Hi I am new to unit testing. Is it possible to access methods that are private?
A very simple example
ObjectA
----------
File file;
private void setupFile (){
//do something
file = "C:\file.dat"
}
In TestCase
File sth = ObjectA.setupFile();
assertNotNull(sth);
I am unable to test whether the file variable is null in method ObjectA.setup()
as I cannot run ObjectA.setupFile()
I am not sure about whether doing like this make sense in terms of unit testing.
So is that a better practice to write every method returning sth and set them public for easier unit testing?
Thanks in advance
In general, you should avoid changing the access of a method/field to enable testing. If you do this then you risk developers using the method directly.
However, if you do need to, then making it protected as Deco says is a good way, so it's accessible from the JUnit tests. If you do this, make sure that it is well documented that this is an method for internal use.
A better way is to test the behaviour of the public methods; you shouldn't care about internal implementation details of a class, so you should only be testing public methods. It's hard to tell from your code, but presumably, the setupFile() has effects later on other methods, so you can test those effects, not the fact that file is not null.
External dependencies (such as dependencies on file system, environment variables) can be worked around in your tests, or injected directly into the class. For the general principle, see my answer to How to test code dependent on environment variables using JUnit?
If it is not absolutely necessary to have the method as private, you can have it as package private (i.e. default access) so that you can call it directly in a JUnit test.
Package private methods can only be used in the package that they are declared, and do not become part of the API of the class. You declare a method package private by putting no modifier on it's declaration.
Here's an example to demonstrate:
public class MyClass() {
int foo;
public MyClass() {
this.foo = 0;
}
void notSoComplexCalculationMethod(int a) {
foo = a * 2;
}
//Other methods here . . .
}
public class MyClassTest extends TestCase {
private MyClass myClass;
protected void setUp() {
super.setUp();
myClass = new MyClass();
}
public void testNotSoComplexCalculationMethod() {
int a = 2;
assertEquals(4, myClass.notSoComplexCalculationMethod(a));
//Unit test passes, yay! Now you've tested a package private method.
}
}

How to mock HTTPSession/FlexSession with TestNG and some Mocking Framework

I'm developing a web application running on Tomcat 6, with Flex as Frontend. I'm testing my backend with TestNG. Currently, I'm trying to test the following method in my Java-Backend:
public class UserDAO extends AbstractDAO {
(...)
public UserPE login(String mail, String password) {
UserPE dbuser = findUserByMail(mail);
if (dbuser == null || !dbuser.getPassword().equals(password))
throw new RuntimeException("Invalid username and/or password");
// Save logged in user
FlexSession session = FlexContext.getFlexSession();
session.setAttribute("user", dbuser);
return dbuser;
}
}
The method needs access to the FlexContext which only exists when i run it on the Servlet container (don't bother if you don't know Flex, it's more a Java-Mocking question in general). Otherwise i get a Nullpointer exception when calling session.setAttribute().
Unfortunately, I cannot set the FlexContext from outside, which would make me able to set it from my tests. It's just obtained inside the method.
What would be the best way to test this method with a Mocking framework, without changing the method or the class which includes the method? And which framework would be the easiest for this use case (there are hardly other things i have to mock in my app, it's pretty simple)?
Sorry I could try out all of them for myself and see how i could get this to work, but i hope that i'll get a quickstart with some good advices!
Obvious one approach is to re-factor it in a way that lets you inject things like the FlexContext. However this is not always possible. Some time ago a team I was part of hit a situation where we had to mock out some internal class stuff that we didn't have access to (like your context). We ended up using an api called jmockit which allows you to effective mock individual methods, including static calls.
Using this technology we where able to get around a very messy server implementation and rather than having to deploy to live servers and black box test, we were able to unit test at a fine level by overriding the server technology that was effective hard coded.
The only recommendation I would make about using something like jmockit is to ensure that in your test code there is clear documentation and seperation of jomockit from you main mocking framework (easymock or mockito would be my recommendations). Otherwise you risk confusing developers about the various responsibilities of each part of the puzzle, which usually leads to poor quality tests or tests that don't work that well. Ideally, as we ended up doing, wrap the jmockit code into you testing fixtures so the developers don't even know about it. Dealing with 1 api is enough for most people.
Just for the hell of it, here's the code we used to fix testing for an IBM class. WE basically need to do two things,
Have the ability to inject out own mocks to be returned by a method.
Kill off a constructor that went looking for a running server.
Do the above without having access to the source code.
Here's the code:
import java.util.HashMap;
import java.util.Map;
import mockit.Mock;
import mockit.MockClass;
import mockit.Mockit;
import com.ibm.ws.sca.internal.manager.impl.ServiceManagerImpl;
/**
* This class makes use of JMockit to inject it's own version of the
* locateService method into the IBM ServiceManager. It can then be used to
* return mock objects instead of the concrete implementations.
* <p>
* This is done because the IBM implementation of SCA hard codes the static
* methods which provide the component lookups and therefore there is no method
* (including reflection) that developers can use to use mocks instead.
* <p>
* Note: we also override the constructor because the default implementations
* also go after IBM setup which is not needed and will take a large amount of
* time.
*
* #see AbstractSCAUnitTest
*
* #author Derek Clarkson
* #version ${version}
*
*/
// We are going to inject code into the service manager.
#MockClass(realClass = ServiceManagerImpl.class)
public class ServiceManagerInterceptor {
/**
* How we access this interceptor's cache of objects.
*/
public static final ServiceManagerInterceptor INSTANCE = new ServiceManagerInterceptor();
/**
* Local map to store the registered services.
*/
private Map<String, Object> serviceRegistry = new HashMap<String, Object>();
/**
* Before runnin your test, make sure you call this method to start
* intercepting the calls to the service manager.
*
*/
public static void interceptServiceManagerCalls() {
Mockit.setUpMocks(INSTANCE);
}
/**
* Call to stop intercepting after your tests.
*/
public static void restoreServiceManagerCalls() {
Mockit.tearDownMocks();
}
/**
* Mock default constructor to stop extensive initialisation. Note the $init
* name which is a special JMockit name used to denote a constructor. Do not
* remove this or your tests will slow down or even crash out.
*/
#Mock
public void $init() {
// Do not remove!
}
/**
* Clears all registered mocks from the registry.
*
*/
public void clearRegistry() {
this.serviceRegistry.clear();
}
/**
* Override method which is injected into the ServiceManager class by
* JMockit. It's job is to intercept the call to the serviceManager's
* locateService() method and to return an object from our cache instead.
* <p>
* This is called from the code you are testing.
*
* #param referenceName
* the reference name of the service you are requesting.
* #return
*/
#Mock
public Object locateService(String referenceName) {
return serviceRegistry.get(referenceName);
}
/**
* Use this to store a reference to a service. usually this will be a
* reference to a mock object of some sort.
*
* #param referenceName
* the reference name you want the mocked service to be stored
* under. This should match the name used in the code being tested
* to request the service.
* #param serviceImpl
* this is the mocked implementation of the service.
*/
public void registerService(String referenceName, Object serviceImpl) {
serviceRegistry.put(referenceName, serviceImpl);
}
}
And here's the abstract class we used as a parent for tests.
public abstract class AbstractSCAUnitTest extends TestCase {
protected void setUp() throws Exception {
super.setUp();
ServiceManagerInterceptor.INSTANCE.clearRegistry();
ServiceManagerInterceptor.interceptServiceManagerCalls();
}
protected void tearDown() throws Exception {
ServiceManagerInterceptor.restoreServiceManagerCalls();
super.tearDown();
}
}
Thanks to Derek Clarkson, I successfully mocked the FlexContext, making the login testable. Unfortunately, it's only possible with JUnit, as far as i see (tested all versions of TestNG with no success - the JMockit javaagent does not like TestNG, See this and this issues).
So this is how i'm doing it now:
public class MockTests {
#MockClass(realClass = FlexContext.class)
public static class MockFlexContext {
#Mock
public FlexSession getFlexSession() {
System.out.println("I'm a Mock FlexContext.");
return new FlexSession() {
#Override
public boolean isPushSupported() {
return false;
}
#Override
public String getId() {
return null;
}
};
}
}
#BeforeClass
public static void setUpBeforeClass() throws Exception {
Mockit.setUpMocks(MockFlexContext.class);
// Test user is registered here
(...)
}
#Test
public void testLoginUser() {
UserDAO userDAO = new UserDAO();
assertEquals(userDAO.getUserList().size(), 1);
// no NPE here
userDAO.login("asdf#asdf.de", "asdfasdf");
}
}
For further testing i now have to implement things like the session map myself. But thats okay as my app and my test cases are pretty simple.