mocking of Logger class method is solution of this error orgapachecommonsloggingLogFactory java.lang.NoClassDefFoundError?

问题描述 投票:0回答:2

我为一个使用Apache logger的类写了一个测试,所以我创建了一个像下面提到的自定义Logger。

 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;
       }
    }

我在我的类中使用了下面提到的这个记录器。

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

如果在我的测试构建中,我包含了像下面提到的commons-apache-logger-dependency,所以我没有得到任何名为java.lang.NoClassDefFoundError的错误:orgapachecommonsloggingLogFactory。

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

但是我不想在我的测试构建中使用这个包含jar的东西,所以有任何其他方法来模拟getInstance()menthod,使它不应该进入logger类中创建日志或任何其他方法来摆脱这个错误。

目前,我正在使用下面提到的Power Mockito,我能够模拟Logger类,但即使在模拟之后,我也得到了错误。

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

错误。

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.

包括下面的起点我试过的testcase类。

//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);
   }
java junit powermockito apache-commons-logging
2个回答
0
投票

在之前尝试模拟静态方法,如。

   @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);
   }

,或者

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

0
投票

你可以这样写你的测试... ...

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;
    //....
   }


© www.soinside.com 2019 - 2024. All rights reserved.