简体   繁体   中英

Is mocking of Logger class method solution of this error org/apache/commons/logging/LogFactory java.lang.NoClassDefFoundError?

I have written a test for a class in which i am using Apache logger, So I have created a Custom Logger like mentioned below.

 import java.io.Externalizable;
    import java.io.IOException;
    import java.io.ObjectInput;
    import java.io.ObjectOutput;
    import java.io.Serializable;

    import java.sql.SQLException;

    import com.medicalis.platform.InternalPlatformException;
    import com.medicalis.platform.MedicalisException;
    import com.medicalis.platform.MedicalisSQLException;
    import com.medicalis.platform.logging.windows.LogSeverity;
    import com.medicalis.platform.logging.windows.WindowsLoggingUtils;

    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;

    public class Logger implements Serializable, Externalizable {
       private Log myLogger = null;
       private String categoryName = null;
       private static final int DEFAULT_EVENT_ID = 9;
       private static final String SQL_STATE_CONSTRAINT_ERROR = "23000";

       /**
        * Creates a new Logger object.
        */
       public Logger() {
       }

       /**
        * Write objects member variables to object stream
        *
        * @param out - ObjectOutput
        *
        * @throws IOException
        */
       public void writeExternal(ObjectOutput out)
          throws IOException {
          out.writeObject(categoryName);
       }

       /**
        * Reads object stream to reconstruct object's member variables
        *
        * @param in - ObjectInput
        *
        * @throws IOException
        * @throws ClassNotFoundException
        */
       public void readExternal(ObjectInput in)
          throws IOException, ClassNotFoundException {
          this.categoryName = (String) in.readObject();
          this.myLogger = LogFactory.getLog(this.categoryName);
       }

       /**
        * Initializes log factory used for all logging.
        *
        * @param log - base logger
        * @param categoryName - String name of logger category
        */
       private Logger(Log log, String categoryName) {
          this.categoryName = categoryName;
          myLogger = log;
       }

       /**
        * Returns a Category instance for the given category name.
        *
        * @param categoryName - String name to use as the name for the log category
        *
        * @return Category logger object
        */
       public static Logger getInstance(final String categoryName) {
          Log log = LogFactory.getLog(categoryName);
          Logger logger = new Logger(log, categoryName);

          return logger;
       }

       /**
        * Returns a Category instance for the given category name.
        *
        * @param categoryClass - Object whose fully qualified classname will be used to determine the
        *        log category
        *
        * @return Category logger object
        */
       public static Logger getInstance(final Class categoryClass) {
          return getInstance(categoryClass.getName().toString());
       }

       /**
        * Logs a message at trace priority.
        *
        * @param obj object whose toString() method is used to get the message to log
        */
       public void trace(Object obj) {
          this.trace((obj == null) ? "null" : obj.toString(), null);
       }

       /**
        * Logs a message at debug priority.
        *
        * @param msg message to log
        * @param t object describing the exception or error that needs to be logged
        */
       public void trace(String msg, Throwable t) {
          myLogger.trace(msg, t);
       }

       /**
        * Logs a message at debug priority.
        *
        * @param obj object whose toString() method is used to get the message to log
        */
       public void debug(Object obj) {
          this.debug((obj == null) ? "null" : obj.toString(), null);
       }

       /**
        * Logs a message at debug priority.
        *
        * @param msg message to log
        * @param t object describing the exception or error that needs to be logged
        */
       public void debug(String msg, Throwable t) {
          myLogger.debug(msg, t);
       }

       /**
        * Logs a message at info priority.
        *
        * @param obj object whose toString() method is used to get the message to log
        */
       public void info(Object obj) {
          this.info((obj == null) ? "null" : obj.toString(), null);
       }

       /**
        * Logs a message at info priority.
        *
        * @param msg message to log
        * @param t object describing the exception or error that needs to be logged
        */
       public void info(String msg, Throwable t) {
          myLogger.info(msg, t);
       }

       /**
        * Logs a message at warn priority.
        *
        * @param obj object whose toString() method is used to get the message to log
        */
       public void warn(Object obj) {
          this.warn((obj == null) ? "null" : obj.toString(), null);
       }

       /**
        * Logs a message at warn priority.
        *
        * @param msg message to log
        * @param t object describing the exception or error that needs to be logged
        */
       public void warn(String msg, Throwable t) {
          myLogger.warn(msg, t);

          if (myLogger.isWarnEnabled()) {
             if (t instanceof MedicalisException) {
                WindowsLoggingUtils.log((MedicalisException) t, LogSeverity.WARNING);
             } else if (t == null) {
                WindowsLoggingUtils.log(msg, DEFAULT_EVENT_ID, LogSeverity.WARNING);
             }
          }
       }

       /**
        * Logs a message at error priority.
        *
        * @param obj object whose toString() method is used to get the message to log
        */
       public void error(Object obj) {
          this.error((obj == null) ? "null" : obj.toString(), null);
       }

       /**
        * Logs a message at error priority.
        *
        * @param msg message to log
        * @param t object describing the exception or error that needs to be logged
        */
       public void error(String msg, Throwable t) {
          myLogger.error(msg, t);

          if (myLogger.isErrorEnabled() && t instanceof MedicalisException) {
             if (!isSQLConstraintError(t)) {
                WindowsLoggingUtils.log((MedicalisException) t, LogSeverity.ERROR);
             }
          }
       }

       /**
        * Returns whether or not trace logging is enabled.
        *
        * @return boolean indicating if trace logging is enabled (true).
        */
       public boolean isTraceEnabled() {
          return myLogger.isTraceEnabled();
       }

       /**
        * Returns whether or not debug logging is enabled.
        *
        * @return boolean indicating if debug logging is enabled (true).
        */
       public boolean isDebugEnabled() {
          boolean isDebug = false;

          isDebug = myLogger.isDebugEnabled();

          if (!isDebug) {
             isDebug = Boolean.getBoolean("system.debug.on");
          }

          return isDebug;
       }

       /**
        * Returns whether or not info logging is enabled.
        *
        * @return boolean indicating if info logging is enabled (true).
        */
       public boolean isInfoEnabled() {
          return myLogger.isInfoEnabled();
       }

       /**
        * Returns whether or not warn logging is enabled.
        *
        * @return boolean indicating if warn logging is enabled (true).
        */
       public boolean isWarnEnabled() {
          return myLogger.isWarnEnabled();
       }

       /**
        * Returns whether or not error logging is enabled.
        *
        * @return boolean indicating if error logging is enabled (true).
        */
       public boolean isErrorEnabled() {
          return myLogger.isErrorEnabled();
       }

       /**
        * Method to determine if the error being thrown is the
        * result of a SQLConstraint Error. (This type of error may be logged
        * differently).
        *
        * @param t Throwable
        *
        * @return boolean
        */
       public boolean isSQLConstraintError(Throwable t) {
          boolean isContraintErr = false;

          Throwable cause = t;

          while (cause != null) {
             if (cause instanceof SQLException) {
                SQLException sqlCause = (SQLException) cause;

                String sqlState = sqlCause.getSQLState();

                if ((sqlState != null) && sqlState.equals(SQL_STATE_CONSTRAINT_ERROR)) {
                   isContraintErr = true;
                }

                break;
             }

             // check for infinite nesting of exceptions
             Throwable lastCause = cause;

             cause = cause.getCause();

             if (cause == lastCause) {
                break;
             }
          }

          return isContraintErr;
       }
    }

I am using this logger in my class like mentioned below.

 private static final Logger log = Logger.getInstance(TimeZoneUtil.class);

If in my test build i am including commons-apache-logger-dependency like mentioned below so i am not getting any error called java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory

<fileset dir="./../thirdparty/commons-logging-1.1.1">
         <include name="*.jar" />
      </fileset>

But I don't want to use this inclusion of jar in my test build so there is any other approach to mock the getInstance() menthod so it should not enter inside the logger class for creating log or any other way to get rid from this error.

currently i am using Power Mockito as mentioned below by which i am able to mock the Logger class but even after mocking it I am getting error.

      PowerMockito.mockStatic(Logger.class);
      Logger logger = mock(Logger.class);
      when(Logger.getInstance(TimeZoneUtil.class)).thenReturn(logger);
      when(Logger.getInstance(any(String.class))).thenReturn(logger);

Error:

Testsuite: com.medicalis.platform.timing.TimeZoneUtilTest
Tests run: 0, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.033 sec

Testcase: com.medicalis.platform.timing.TimeZoneUtilTest took 0 sec
    Caused an ERROR
org/apache/commons/logging/LogFactory
java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
    at com.medicalis.platform.logging.Logger.getInstance(Logger.java:107)
    at com.medicalis.platform.logging.Logger.getInstance(Logger.java:122)
    at com.medicalis.platform.timing.TimeZoneUtil.<clinit>(TimeZoneUtil.java:30)
    at com.medicalis.platform.timing.KnownTimeZone.loadValuesImpl(KnownTimeZone.java:51)
    at com.medicalis.platform.timing.TimeZoneUtilTest.setUp(TimeZoneUtilTest.java:69)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory
    at java.lang.ClassLoader.loadClass(ClassLoader.java:352)

Please help me by giving some good approach so i should not get this error it can be mocking of object mocking of method or any other approach which can solve this problem except providing dependency in test build thank you in advance.

Including below starting point of my tried testcase class.

//import static org.easymock.EasyMock.mock;
import static org.junit.Assert.*;

import java.sql.SQLException;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import javax.sql.RowSet;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONArray;
import org.json.JSONException;
import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.powermock.api.mockito.PowerMockito.*;

import static org.mockito.Matchers.*;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
//import static org.easymock.EasyMock.expect;
import com.medicalis.common.shared.UUIDHelper;
import com.medicalis.platform.logging.Logger;
import com.medicalis.platform.user.valueobject.UserData;
//import static org.powermock.api.easymock.PowerMock.mockStatic;

@RunWith(PowerMockRunner.class)
@PrepareForTest({Logger.class, LogFactory.class, TimeZoneUtil.class, KnownTimeZone.class})
public class TimeZoneUtilTest {
   public static final String UNIT_TEST_PROPERTY = "timeZoneUtilsUnitTestRunning";
   private static final String EUCLA_TZ = "Australia/Eucla";
   private static final String LA_TZ = "America/Los_Angeles";
   private static final String PERTH_TZ = "Australia/Perth";
   private static final String AUSTRALIA_PERTH_SHORT_CD = "APER";
   private static final String PERTH_TZ_JSON = "[{'timeZoneCd': 'APER', 'javaId': 'Australia/Perth', 'displayCode': 'AWST', 'timeZoneId': 12, 'windowsId': '(UTC+08:00) Perth'}]";

   private static List javaIdTestValue, timeZonesTestValue;
   private static UserData professionalUserData, rmUserData;

   /*package*/ static boolean isUnitTestRunning() {
      return String.valueOf(true).equals(System.getProperty(TimeZoneUtilTest.UNIT_TEST_PROPERTY));
   }

   @BeforeClass
   public static void setUp() throws SQLException, JSONException {

     /* mockStatic(LogFactory.class);
      Log log = mock(Log.class);
      when(LogFactory.getLog(anyString())).thenReturn(log);
   */

     mockStatic(Logger.class);
      Logger logger = mock(Logger.class);
     // expect(Logger.getInstance(TimeZoneUtil.class)).andReturn(logger);

     when(Logger.getInstance(TimeZoneUtil.class)).thenReturn(logger);
      when(Logger.getInstance(any(String.class))).thenReturn(logger);

      when(logger.isDebugEnabled()).thenReturn(Boolean.valueOf("true"));

      doNothing().when(logger).error(anyString(),any());
      doNothing().when(logger).warn(anyString(),any());

      doNothing().when(logger).debug(anyString(),any());

     doNothing().when(logger).error(anyString(),any());
      System.setProperty(UNIT_TEST_PROPERTY, String.valueOf(true));

      RowSet rowSet = new TimeZoneUtilTestRowSet();
      rowSet.next();
      rowSet.setString("javaId", EUCLA_TZ);
      javaIdTestValue = Collections.singletonList(rowSet);

      RowSet timeZoneRowSet = new TimeZoneUtilTestRowSet(new JSONArray(PERTH_TZ_JSON));
      timeZonesTestValue = Collections.singletonList(timeZoneRowSet);
      KnownTimeZone.loadValuesImpl(timeZonesTestValue);

      professionalUserData = new UserData() {
         @Override
         public boolean isProfessionalContext() {
            return true;
         }

         @Override
         public String getProfessionalTimeZoneId() {
            return LA_TZ;
         }
      };
      professionalUserData.setPreferredTimeZone(AUSTRALIA_PERTH_SHORT_CD);

      rmUserData = new UserData();
      rmUserData.setPreferredTimeZone(AUSTRALIA_PERTH_SHORT_CD);
   }

In before try to mock static method like:

   @Before
   public void before() throws Exception {
      mockStatic(LogFactory.class);
      Log log = mock(Log.class);
      when(LogFactory.getLog(anyString())).thenReturn(log);
      when(LogFactory.getLog(any(Class.class))).thenReturn(log);
   }

, or

   @Before
   public void before() throws Exception {
     mockStatic(Logger.class);
     Logger logger = mock(Logger.class);
     when(Logger.getInstance(any())).thenReturn(logger);
   }

you can write your test like this...

public class TimeZoneUtilTest {
   public static final String UNIT_TEST_PROPERTY = "timeZoneUtilsUnitTestRunning";
   private static final String EUCLA_TZ = "Australia/Eucla";
   private static final String LA_TZ = "America/Los_Angeles";
   private static final String PERTH_TZ = "Australia/Perth";
   private static final String AUSTRALIA_PERTH_SHORT_CD = "APER";
   private static final String PERTH_TZ_JSON = "[{'timeZoneCd': 'APER', 'javaId': 'Australia/Perth', 'displayCode': 'AWST', 'timeZoneId': 12, 'windowsId': '(UTC+08:00) Perth'}]";

   private static List javaIdTestValue, timeZonesTestValue;
   private static UserData professionalUserData, rmUserData;

    @Mock
    Logger logger;
    //....
   }


The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM