I am trying to create a minimalist test class for testing some of my CouchBase Lite Mobile classes. I have tried mocking the Application context but have been unsuccessful.
The problem is that the CouchBase manager is accessing some of the unimplemented methods on the MockContext class.
Here are my approaches so far below:
public class ClassToTest extends TestCase {
#Test
public void testGetAllDocumentsBundle() throws Exception {
try {
Manager manager = new Manager(
new AndroidContext(new MockContext()),
Manager.DEFAULT_OPTIONS);
}
catch (Exception e) {
Log.e(TAG, "Exception: " + e);
assertTrue(false);
}
}
And:
#RunWith(AndroidJUnit4.class)
public class ItemReaderTest {
private android.content.Context instrumentationCtx;
#Before
public void setUp() throws Exception {
instrumentationCtx = InstrumentationRegistry.getContext();
}
...
#Test
public void testGetAllDocumentsBundle() throws Exception {
Database database = null;
String databaseName = "test";
try {
Context context = new AndroidContext(instrumentationCtx);
Assert.assertTrue(context != null);
Manager manager = new Manager(context, Manager.DEFAULT_OPTIONS); <--- throws exception because context.getFilesDir(); return null in Couchbase Manager.java constructor
...
}
}
Has anyone been able to do this? Do I absolutely have to use an actual Activity (i.e. create an actual mobile Application and use it's context to be able to test Couchbase mobile at all?
I was able to successfully create the manager and database by doing this:
class MyMockContext extends MockContext {
#Override
public File getFilesDir(){
File f = new
File("/data/user/0/com.example.mypackagename/files");
return f;
}
}
And initializing the manager with this context:
Context context = new AndroidContext(new MyMockContext());
Manager manager = new Manager(context, Manager.DEFAULT_OPTIONS);
However this does make the test dependent on a specific environment and hard-coded path. Perhaps there is a better solve out there...
Related
I want to make periodical REST request with a Dropwizard Backend. More concretely I want to make an GET request to an external REST API every minute and process the result.
I used the quartz here and now I try to use the jersey client to make a REST request. I use guice as my dependency injection.
My application class has the following methods
#Override
public void initialize(final Bootstrap<DockerwizardConfiguration> bootstrap) {
Job everyJob = new EveryTestJob();
bootstrap.addBundle(new JobsBundle(everyJob));
}
#Override
public void run(final DockerwizardConfiguration configuration,
final Environment environment) {
Injector injector = Guice.createInjector(new AbstractModule() {
#Override
protected void configure() {
bind(HelloWorldParameter.class)
.annotatedWith(Names.named("helloWorldParameter"))
.toInstance(configuration.getHelloWorldParameter());
}
});
JerseyClientConfiguration conf = configuration.getJerseyClientConfiguration();
conf.setChunkedEncodingEnabled(false);
final Client client = new JerseyClientBuilder(environment).using(conf).build(getName());
environment.jersey().register(new ExternalServiceResource(client)); // How should that be implented with guice
environment.jersey().register(injector.getInstance(HelloWorldResource.class));
}
And my EveryTestJob class is implemented as follows
#Every("1s")
public class EveryTestJob extends Job {
#Override
public void doJob(JobExecutionContext context) throws JobExecutionException {
// logic run every time and time again
}
}
I am unsure how I this can be organized.
I've been trying to figure this out for a while, and this is what I have found out:
The JobBundle is added before any Resources so the JobExecutionContext will not include the client (https://www.dropwizard.io/0.9.2/docs/manual/internals.html)
Tried using the injector but didn't work either (https://github.com/HubSpot/dropwizard-guice)
Finally I stumbled on Jersey 2.0: Create repeating job which showed how to add the client into the context!
Here's my solution:
In the resource class,
#Path("/myPath")
public class myResource {
#Inject
public myResource() {
try {
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.getContext().put"myResource", this); // Inserts myResource into the context
} catch (SchedulerException e) {
// Handle exception
}
}
// Other stuff for api
}
Then in the job class (I'm using Dropwizard-jobs 2.0.1 where doJobs doesn't take in any arguments so I used execute instead),
#Every("10s")
public class myJob extends Job {
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
try {
myResource res = (myResource) context.getScheduler().getContext().get("myResource");
// Do stuff with your resource
} catch (SchedulerException e) {
// Handle exception
}
}
}
Not sure if you have access to the ExternalServiceResource, but I hope this helps!
when I try to mock following method(Method is using remote EJB call for business logic) for the Junit test, it gives javax.naming.NoInitialContextException
private void someMethod(int id1, int id2, HashMap map){
......some code........
Context ctx = new InitialContext();
Object ref = ctx.lookup("com.java.ejbs.MyEJB");
EJBHome ejbHome = (EJBHome)PortableRemoteObject.narrow(ref, EJBHome.class);
EJBBean ejbBean = (EJBBean)PortableRemoteObject.narrow(ejbHome.create(), EJBBean.class);
ejbBean.someMethod(id1,name);
.......some code.......}
My unit test for above method
#Test
public void testsomeMethod() throws Exception {
.......setting initial code...
//Mock context and JNDI
InitialContext cntxMock = PowerMock.createMock(InitialContext.class);
PowerMock.expectNew(InitialContext.class).andReturn(cntxMock);
expect(cntxMock.lookup("com.java.ejbs.MyEJB")).andReturn(refMock);
..........some code..........
PowerMock.replayAll();
Whitebox.invokeMethod(ObjectOfsomeMethodClass, "someMethod", id1, id2, map);
}
when the Whitebox.invokeMethod(ObjectOfsomeMethodClass, "someMethod", id1, id2, map) method invokes it gives following exception.
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:645)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:325)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
I believe, although we mock the Context in test method, it does not use the mock object when calling Whitebox.invokeMethod(ObjectOfsomeMethodClass, "someMethod", id1, id2, map) method, instead of that its trying to invoke the Context ctx = new InitialContext(); method in original method(someMethod).
Handmade
As InitialContext doc says, you can provide your own factory for InitialContext objects, using java.naming.factory.initial system property. When the code runs inside application server, the system property is set by the server. In our tests, we provide our own implementation of JNDI.
Here's my Mockito only solution: I defined a custom InitialContextFactory class, that returns a mock of InitialContext. You customize the mock as you wish, probably to return more mocks on lookup calls.
public class PlainTest {
#Mock InitialContextFactory ctx;
#InjectMocks Klasa1 klasa1;
public static class MyContextFactory implements InitialContextFactory
{
#Override
public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
ConnectionFactory mockConnFact = mock(ConnectionFactory.class);
InitialContext mockCtx = mock(InitialContext.class);
when(mockCtx.lookup("jms1")).thenReturn(mockConnFact);
return mockCtx;
}
}
#Before
public void setupClass() throws IOException
{
MockitoAnnotations.initMocks(this);
System.setProperty("java.naming.factory.initial",
this.getClass().getCanonicalName() + "$MyContextFactory");
}
Spring (added by edit)
If you don't mind leveraging Spring Framework for testing purposes, here's their simple solution: SimpleNamingContextBuilder:
SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
DataSource ds = new DriverManagerDataSource(...);
builder.bind("java:comp/env/jdbc/myds", ds);
builder.activate();
It's ok to put it in #Before or #BeforeClass. After activate(), jndi data will be pulled from spring dummy.
Adding to Jarekczek's answer (Thanks for it!!). Though it is an old question I would like to share my version of it in case it helps someone. I faced the same problem and one might just want to mock IntialContext only in a IntialContextFactory implementation class and it would be a better idea to use this mocked object in other tests or base test classes to avoid duplication.
public class MyContextFactory implements InitialContextFactory {
// Poor Singleton approach. Not thread-safe (but hope you get the idea)
private static InitialContext mockInitialContext;
#Override
public Context getInitialContext(Hashtable<?,?> hshtbl) throws NamingException {
if(mockInitialContext == null) {
mockInitialContext = mock(InitialContext.class);
}
return mockInitialContext;
}
}
public class TestClass {
private DataSource mockDataSource;
private Connection mockConnection;
protected void mockInitialContext() throws NamingException, SQLException {
System.setProperty("java.naming.factory.initial", "com.wrapper.MyContextFactory");
InitialContext mockInitialContext = (InitialContext) NamingManager.getInitialContext(System.getProperties());
mockDataSource = mock(DataSource.class);
mockConnection = mock(Connection.class);
when(mockInitialContext.lookup(anyString())).thenReturn(mockDataSource);
when(mockDataSource.getConnection()).thenReturn(mockConnection);
try {
when(mockDataSource.getConnection()).thenReturn(mockConnection);
} catch (SQLException ex) {
Logger.getLogger(CLASSNAME).log(Level.SEVERE, null, ex);
}
}
}
Reason behind taking this approach being if someone wants to use DataSource or any other resource provided by JNDI in a different way for different tests, you can follow this approach. There shall be just one instance created for IntialContext unless a multi-threaded test tries to access it simultaneously (don't know why would one try to do that!). That instance can be used in all places to get JNDI objects you want and use them as you want.
Hope this helps!
"Make sure you wash your hands before every meal and avoid System.out.println while debugging for healthy lifestyle"
You can refactor your code and extract the initialization of the context in new method.
private void someMethod(int id1, int id2, HashMap map){
......some code........
Context ctx = getInitialContext();
Object ref = ctx.lookup("com.java.ejbs.MyEJB");
EJBHome ejbHome = (EJBHome)PortableRemoteObject.narrow(ref, EJBHome.class);
EJBBean ejbBean = (EJBBean)PortableRemoteObject.narrow(ejbHome.create(), EJBBean.class);
ejbBean.someMethod(id1,name);
.......some code.......}
Your test code will be something like this:
Context mockContext = mock(Context.class);
doReturn(mockContext).when(yourclass).getInitalContext();
...... some code....
As of now (PowerMock 1.7.4)
Create a mock using PowerMockito.mock(InitialContext.class) rather than PowerMockito.createMock(InitialContext.class)
#Test
public void connectTest() {
String jndi = "jndi";
InitialContext initialContextMock = PowerMockito.mock(InitialContext.class);
ConnectionFactory connectionFactoryMock = PowerMockito.mock(ConnectionFactory.class);
PowerMockito.whenNew(InitialContext.class).withNoArguments().thenReturn(initialContextMock);
when(initialContextMock.lookup(jndi)).thenReturn(connectionFactoryMock);
...
// Your asserts go here ...
}
Do not create the InitialContext manually but let PowerMock do it for you. Also do not create a spy in which PowerMock expects an object. This means that you need to create the InitialContext instance.
Define the following Custom Classes
public static class CustomInitialContext extends InitialContext {
Hashtable<String, Object> ic = new Hashtable<>();
public CustomInitialContext() throws NamingException {
super(true);
}
public void bind(String name, Object object) {
ic.put(name, object);
}
public Object lookup(String name) throws NamingException {
return ic.get(name);
}
}
public static class CustomInitialContextFactory implements InitialContextFactory {
static InitialContext ic;
public CustomInitialContextFactory() {
if (ic == null) {
try {
ic = new CustomInitialContext();
} catch (NamingException e) {
e.printStackTrace();
}
}
}
public Context getInitialContext(Hashtable<?, ?> arg0) throws NamingException {
return ic;
}
}
public static class CustomInitialContextFactoryBuilder implements InitialContextFactoryBuilder {
#Override
public InitialContextFactory createInitialContextFactory(Hashtable<?, ?> environment) throws NamingException {
return new CustomInitialContextFactory();
}
}
and declare factory as
NamingManager.setInitialContextFactoryBuilder(new CustomInitialContextFactoryBuilder());
My project is not Spring based .Its a java with Hibernate.Building tool - Maven.
I am loading data from one database to HSQL DB before running junits.
My DB util class:
public class DatabaseUtil {
SchemaLoad schemaLoad = new SchemaLoad();
DataLoad dataLoad = new DataLoad();
boolean dataLoaded = false;
static final String filename1 = "test1.txt";
static final String filename2 = "text2.txt";
void dbLoad() throws SQLException {
if (!dataLoaded) {
schemaLoad.cloneSchema(filename1);
dataLoad.exportData(filename2);
System.out.println("***********executed**********8");
dataLoaded = true;
}
}
}
First Test Case:
public class TestCase {
TrainRepository trainRepository = new TrainRepositoryImpl();
DatabaseUtil databaseUtil = new DatabaseUtil();
#BeforeClass
private void setUp() throws SQLException {
databaseUtil.dbLoad();
}
#Test
private void positiveTestCaseForTrainRepo() throws Exception {
//TestCases
}
Second Test case:
public class TestCase1 {
AirRepository airRepository = new AirRepositoryImpl();
DatabaseUtil databaseUtil = new DatabaseUtil();
#BeforeClass
private void setUp() throws SQLException {
databaseUtil.dbLoad();
}
#Test
private void positiveTestCaseForAirRepo() throws Exception {
//TestCases
}
Both the test cases are running fine.But Its executing databaseUtil.dbLoad(); method on each junit.
My question is I need to load the database only once ie before start of first junit and need to set some indicator .The further junits need to check the DB instance If DB instance is there it should not load the data ie DatabaseUtil class need to be singleton.
All the junits are running through maven suffire plugin during mvn install phase.
Kindly help me to achieve this.
void dbLoad() will be called each time.
then use a static variable to keep track
static boolean dataLoaded = false;
if you don't use spring you need to implement caching yourself. you have a few option. use static field with some kind of synchronization (in case you use/plan to use threads). other option is to switch to testng that gives you #BeforeGroup functionality so you can mark all your db tests and have your initialization run before.
I am trying to test something like this:
try {
logger.info("message");
//do something
} catch(Exception e) {
logger.error(errorMessage);
}
I know that it's not a good practice to catch an Exception, but there is some legacy code and there is no time for refactoring.
So, I write an unit test so that a NullPointerException will be thrown inside try block, but now I don't know how to write the assert line(obviously, unit test have to fail all the time).
Please notice that I can`t use:
final Logger logger = LogManager.getLogger(AnaliticsService.class);
final Appender mockAppender = mock(Appender.class);
logger.addAppender(mockAppender);
final ArgumentCaptor<LoggingEvent> captor = ArgumentCaptor.forClass(LoggingEvent.class);
Log4jConfigHelper.getInstance().bufferConfiguration();
verify(mockAppender, times(x)).doAppend(captor.capture());
because I don`t know how many messages are logged when UT is running.
You should try to make a Mock for LoggerFactory.
First annotate your TestClass with:
#RunWith(PowerMockRunner.class)
#PrepareForTest({YourController.class, LoggerFactory.class})
Then make a test, which calls needed method and veryfies errors:
#Test
public void testErrorLogging() throws Exception {
mockStatic(LoggerFactory.class);
Logger logger = mock(Logger.class);
when(LoggerFactory.getLogger(any(Class.class))).thenReturn(logger);
YourController controller = new YourController();
controller.someMethod();
verify(logger).error(anyString());
}
Log messages are part of the user interface of your code. Code that does computations should not make assumptions about the manner in which log messages are made available to the user, the text and language of the log messages, or even whether messages are communicated as text (rather than, say, a graphical means). So computational code should delegate to an associated logger class (in the UI/presentation layer) that hides all those details.
If the computational code only requires that the associated logger conforms to an interface, and uses dependency injection for being associated with a logger class, it is easy to mock the logger to examine whether the computational code has requested logging.
So if the code to be tested is like this::
public class MyService
{
private final MyServiceLogger logger;
MyService(MyServiceLogger logger)
{
this.logger = Objects.requireNonNull(logger);
}
public void processFile(Path path) {
...
try{
...
} catch (EOFException e) {
logger.logUnexpectedEOF(path);
}
}
}
public interface MyServiceLogger
{
public logUnexpectedEOF(Path path);
}
public class MyServiceTextLogger implements MyServiceLogger
{
private final Logger textLogger = LogManager.getLogger(MyService.class);;
#Override
public logUnexpectedEOF(Path path) {
textLogger.error("unexpected EOF for file {}",path);
}
}
You can test it like this:
public class MyServiceTest
{
private static class MockMyServiceLogger implements MyServiceLogger
{
private Path path;
private int nCalls_logUnexpectedEOF;
#Override
public logUnexpectedEOF(Path path) {
++nCalls_logUnexpectedEOF;
this.path = path;
}
void assertCalled_logUnexpectedEOF(int nCalls, Path path) {
assertEquals("Called logUnexpectedEOF, nCalls", nCalls, nCalls_logUnexpectedEOF);
assertEquals("Called logUnexpectedEOF, path", path, this.path);
}
}
#Test
public void processFile_unexpectedEOF() {
Path testPath = ...
...
MockMyServiceLogger mockLogger = new MockMyServiceLogger();
MyService service = new MyService(mockLogger);
service.processFile(testPath);
mockLogger.assertCalled_logUnexpectedEOF(1, testPath);
}
#Test
public void processFile_OK() {
Path testPath = ...
...
MockMyServiceLogger mockLogger = new MockMyServiceLogger();
MyService service = new MyService(mockLogger);
service.processFile(testPath);
mockLogger.assertCalled_logUnexpectedEOF(0, null);
}
}
I write an unit test so that a NullPointerException will be thrown inside try block, but now I don't know how to write the assert line(obviously, unit test have to fail all the time).
You don't need to check for an exception this way. A test which throws an Exception fails.
} catch(Exception e) {
logger.error(errorMessage, e);
throw e; // report the error to the test
}
Note: when to throw an error to the testing framework it will log/print it so I suspect you don't need to be catching it in the first place.
We're transitioning from using TestNG with an embedded JBoss to using Arquillian with a remote server.
We are running a simple test that has a method annotated with #BeforeClass that does some test setup. After a lot of digging, it looks like that setup method is being called twice: once on the console where we're executing our Maven command to run the test and again when the test war is deployed to our remote server and the test runs. These are two separate JVMS - one running outside the container and another running inside the container. My preference is to just have the latter run.
Is this the behavior I should expect or is there something I may be missing?
For now, we're actually checking to see if we're in the container or not and, if so, we run our setup code. This works but I'd like to know if there's a better way.
Some snippets of our code (please ignore the simplicity of the code and the fact that the setupComponents method really isn't needed here, there are much more complicated tests that we're migrating that will need this functionality):
public class BaseTest extends Arquillian
{
private static Log log = LogFactory.getLog( SeamTest.class );
#Deployment
public static Archive<?> createDeployment()
{
// snip... basically, we create a test war here
}
/**
* todo - there might be a better way to do this
*/
private boolean runningInContainer()
{
try
{
new InitialContext( ).lookup( "java:comp/env" );
return true;
}
catch (NamingException ex)
{
return false;
}
}
#BeforeClass
public void setupOnce() throws Exception
{
getLog().debug( "in setupOnce(): " + runningInContainer() );
if ( runningInContainer() )
{
new ComponentTest()
{
protected void testComponents() throws Exception
{
setupComponents();
}
}.run();
}
}
public User createUser()
{
// ...
}
public Log getLog()
{
// snip...
}
public UserDao getUserDao()
{
// ...
}
public abstract class ComponentTest
{
protected abstract void testComponents() throws Exception;
public void run() throws Exception
{
try {
testComponents();
} finally {
}
}
}
}
public class UserDaoTest extends BaseTest
{
UserDao userDao;
#Override
protected void setupComponents()
{
getLog().debug( "in setupComponents: " + runningInContainer() );
userDao = getUserDao();
}
#Test
public void testGetUser() throws Exception
{
getLog().debug( "in testGetUser: " + runningInContainer() );
new ComponentTest()
{
protected void testComponents() throws Exception
{
User user0 = createUser();
user0.setName( "frank" );
userDao.merge( user0 );
User retrievedUser = userDao.findByName( "frank" );
assertNotNull( retrievedUser );
}
}.run();
}
}
This basically gives me output that looks like this:
From the console where mvn is being executed:
in setupOnce(): false
From the jboss server:
in setupOnce(): true
in setupComponents: true
in testGetUser: true
This is "expected" behaviour. Not really nice, but it is how Arqullian works.
JUnit
#BeforeClass / #AfterClass are only executed on ClientSide
The state of the test class is lost between #Test, in container the whole lifecycle is repeated for each test
#Before / #After are executed depending on the runmode (client/server)
TestNG
everything is run both on server and client