java - 通过枚举对 Singleton 进行单元测试抛出 java.lang.NoClassDefFoundError

标签 java unit-testing enums singleton testng

这很奇怪,我不确定如何解释清楚。请耐心等待并查看代码片段以了解详细信息。

我使用枚举实现了一个单例。枚举有一个私有(private)构造函数,在构造对象之前我在其中进行了一些操作和验证。对于所有这些验证,我抛出了一些异常(比如 IllegalArgumentException)。

我的测试用例包括针对消极和积极场景的测试。每当有 2 个以上的测试用例混合使用负面和正面测试用例时,我都会收到以下异常:java.lang.NoClassDefFoundError: Could not initialize class com.blah.blah.SingletonClass。请检查下面的完整代码。我正在使用以下技术堆栈:

JDK 1.7_51
Spring 4.0.0.RELEASE
testng 6.8.7

单例使用枚举.java

public enum SingletonUsingEnum {
  INSTANCE;

  // Logger
  private final Logger logger = LoggerFactory.getLogger(SingletonUsingEnum.class);

  private SingletonUsingEnum() {
    final MyConfig myConfig = MyConfigManager.getMyConfig();
    if(myConfig == null) {
      throw new IllegalArgumentException("MyConfig is null");
    }

    if(StringUtils.isBlank(myConfig.getConfigValue())) {
      throw new IllegalArgumentException("myConfig.configValue value null/empty");
    }

    if(StringUtils.isBlank(myConfig.getOtherConfigValue())) {
      throw new IllegalArgumentException("myConfig.otherConfigValue null/empty");
    }

    logger.info("This is a singleton using enum");
  } 
}

MyConfig.java

public class MyConfig {
  private String configValue;
  private String otherConfigValue;

  public MyConfig(final String configValue, final String otherConfigValue) {
    this.configValue = configValue;
    this.otherConfigValue = otherConfigValue;
  }

  public String getConfigValue() {
    return configValue;
  }

  public String getOtherConfigValue() {
    return otherConfigValue;
  } 
}

MyConfigManager.java

public class MyConfigManager {
  private final static ConcurrentMap myConfigHolder = new ConcurrentHashMap();

  public static void registerMyConfig(final MyConfig myConfig) {
    myConfigHolder.put("myConfig", myConfig);
  }

  public static MyConfig getMyConfig() {
    return myConfigHolder.get("myConfig");
  }

  public static void clearAll() {
    myConfigHolder.clear();
  }
}

SingletonUsingEnumTest.java

@ContextConfiguration(classes = {SingletonUsingEnumTest.SpringConfig.class})
public class SingletonUsingEnumTest extends AbstractTestNGSpringContextTests {
  // Logger
  private static final Logger logger = LoggerFactory.getLogger(SingletonUsingEnumTest.class);

  @AfterMethod
  public void cleanUp() {
    MyConfigManager.clearAll();
  }

  @Test(expectedExceptions = {IllegalArgumentException.class, ExceptionInInitializerError.class})
  public void nullMyConfig() {
    MyConfigManager.registerMyConfig(new MyConfig("", ""));
    final SingletonUsingEnum singleton = SingletonUsingEnum.INSTANCE;
  }

  @Test
  public void validMyConfig_nullConfigValue() {
    MyConfigManager.registerMyConfig(new MyConfig("", "b"));
    final SingletonUsingEnum singleton = SingletonUsingEnum.INSTANCE;
  }

  @Test(dependsOnMethods = {"nullMyConfig"})
  public void allValidData() {
    MyConfigManager.registerMyConfig(new MyConfig("a", "b"));
    final SingletonUsingEnum singleton = SingletonUsingEnum.INSTANCE;
  }

  @Configuration
  @EnableAspectJAutoProxy(proxyTargetClass = true)
  public static class SpringConfig {

  }
}

测试执行的结果如下所示。我特意将 expectedExceptions 添加到第一个测试以隐藏第一个测试的堆栈跟踪。

[TestNG] Running:
  /private/var/folders/l6/hmmqvjpj13ggmyc69sk1s5740000gn/T/testng-eclipse-135911498/testng-customsuite.xml

PASSED: nullMyConfig
FAILED: validMyConfig_nullConfigValue
java.lang.NoClassDefFoundError: Could not initialize class com.demo.singleton.SingletonUsingEnum
    at com.demo.singleton.SingletonUsingEnumTest.validMyConfig_nullConfigValue(SingletonUsingEnumTest.java:38)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
    at org.testng.internal.MethodInvocationHelper$1.runTestMethod(MethodInvocationHelper.java:200)
    at org.springframework.test.context.testng.AbstractTestNGSpringContextTests.run(AbstractTestNGSpringContextTests.java:157)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.testng.internal.MethodInvocationHelper.invokeHookable(MethodInvocationHelper.java:212)
    at org.testng.internal.Invoker.invokeMethod(Invoker.java:707)
    at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
    at org.testng.TestRunner.privateRun(TestRunner.java:767)
    at org.testng.TestRunner.run(TestRunner.java:617)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
    at org.testng.SuiteRunner.run(SuiteRunner.java:240)
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
    at org.testng.TestNG.run(TestNG.java:1057)
    at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
    at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
    at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)

FAILED: allValidData
java.lang.NoClassDefFoundError: Could not initialize class com.demo.singleton.SingletonUsingEnum
    at com.demo.singleton.SingletonUsingEnumTest.allValidData(SingletonUsingEnumTest.java:44)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
    at org.testng.internal.MethodInvocationHelper$1.runTestMethod(MethodInvocationHelper.java:200)
    at org.springframework.test.context.testng.AbstractTestNGSpringContextTests.run(AbstractTestNGSpringContextTests.java:157)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.testng.internal.MethodInvocationHelper.invokeHookable(MethodInvocationHelper.java:212)
    at org.testng.internal.Invoker.invokeMethod(Invoker.java:707)
    at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
    at org.testng.TestRunner.privateRun(TestRunner.java:767)
    at org.testng.TestRunner.run(TestRunner.java:617)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
    at org.testng.SuiteRunner.run(SuiteRunner.java:240)
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
    at org.testng.TestNG.run(TestNG.java:1057)
    at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
    at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
    at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)


===============================================
    Default test
    Tests run: 3, Failures: 2, Skips: 0
===============================================


===============================================
Default suite
Total tests run: 3, Failures: 2, Skips: 0
===============================================

[TestNG] Time taken by org.testng.reporters.JUnitReportReporter@6997f7f4: 8 ms
[TestNG] Time taken by org.testng.reporters.XMLReporter@4474c7fe: 14 ms
[TestNG] Time taken by [FailedReporter passed=0 failed=0 skipped=0]: 6 ms
[TestNG] Time taken by org.testng.reporters.SuiteHTMLReporter@395e7bc4: 14 ms
[TestNG] Time taken by org.testng.reporters.EmailableReporter2@71419cf7: 5 ms
[TestNG] Time taken by org.testng.reporters.jq.Main@6015eb5a: 31 ms

如果有人能帮我解释发生了什么,我将不胜感激。

谢谢,NN

最佳答案

您的测试尝试使用您的单例。所以 JVM 加载并初始化枚举。作为此过程的一部分,它会调用您的构造函数来初始化唯一的枚举实例。构造函数抛出异常,阻止类被正确加载。

一旦 JVM 尝试加载该类但失败,它就不会再尝试加载它。

单例是一种反模式。在加载其类时急切初始化的单例中执行这种导致异常的过程是一个非常糟糕的主意。

关于java - 通过枚举对 Singleton 进行单元测试抛出 java.lang.NoClassDefFoundError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22849995/

相关文章:

java - jmockit 捕获模拟方法参数

c# - 单元测试 ASP.NET Core HttpResponse.OnStarting()

C++ - 对声明枚举感到困惑

java - 是否可以使用包含两个或更多单词的枚举的枚举类?

java - 创建具有多个客户端的服务器

java - SwingUtilities.updateComponentTreeUI() 方法是否将当前 L&F 设置为所有 super 组件和子组件?

java - 使用 java 从 aws 获取主题 ARN

android - 使用android studio进行单元测试时运行哪个测试

c++ - 在 C++ 中键入安全(r)位标志?

java - 自动完成功能在 Apache ISIS Action 中不起作用