【问题标题】:no injection of a mock with easymock不用easymock注入模拟
【发布时间】:2017-11-11 22:25:34
【问题描述】:

我想使用 easymock 3.5 和 JUnit5 编写一个小示例,但在尝试注入 mock 时出现错误 (nullPointerException)...

这里是测试代码:

package model;

import controler.BookEditor;
import org.easymock.EasyMockRule;
import org.easymock.EasyMockSupport;
import org.easymock.Mock;
import org.easymock.TestSubject;
import org.junit.Before;
import org.junit.Rule;
import org.junit.jupiter.api.Test;
import view.BookWindow;

import static org.junit.jupiter.api.Assertions.assertEquals;

//@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class BookTest extends EasyMockSupport {

@Rule
public EasyMockRule rule = new EasyMockRule(this);


@Mock
public BookWindow bookWindow;

public BookList bookList;

@TestSubject
public BookEditor bookEditor;

@Before
public void setUp() {
  bookList = new BookList();
  bookEditor = new BookEditor(bookList, bookWindow);
}

@Test
public void testBookCreation() {

  Book le_livre_de_la_jungle = new Book("Le livre de la jungle", "Rudyard Kipling",
        "Flammarion",
        "978-2081263246");
  assertEquals(le_livre_de_la_jungle.getTitle(), "Le livre de la jungle");
  assertEquals(le_livre_de_la_jungle.getAuthor(), "Rudyard Kipling");
  assertEquals(le_livre_de_la_jungle.getEditor(), "Flammarion");
  assertEquals(le_livre_de_la_jungle.getISBN(), "978-2081263246");

}


@Test
public void testDisplayBook() {
  bookWindow.setTitle("Le livre de la jungle"); //here is line 53
  bookWindow.setAuthor("Rudyard Kipling");
  bookWindow.setEditor("Flammarion");
  bookWindow.setISBN("978-2081263246");
  replayAll();

  bookEditor.setActiveBook(new Book("Le livre de la jungle",
        "Rudyard Kipling", "Flammarion", "978-2081263246"));
  verifyAll();

}

}

第一次测试没问题,但 testDisplayBook 失败,因为 bookWindow 为空。

在我的 POM 中,我有这个:

<dependencies>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.junit.platform</groupId>
        <artifactId>junit-platform-launcher</artifactId>
        <version>RELEASE</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>RELEASE</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.junit.vintage</groupId>
        <artifactId>junit-vintage-engine</artifactId>
        <version>4.12.1</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.junit.platform</groupId>
        <artifactId>junit-platform-runner</artifactId>
        <version>RELEASE</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.easymock</groupId>
        <artifactId>easymock</artifactId>
        <version>3.5</version>
        <scope>test</scope>
    </dependency>

</dependencies>

这里是个例外:

java.lang.NullPointerException 在 model.BookTest.testDisplayBook(BookTest.java:53) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:498) 在 org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:389) 在 org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115) 在 org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:167) 在 org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40) 在 org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:163) 在 org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:110) 在 org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:57) 在 org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.lambda$execute$3(HierarchicalTestExecutor.java:83) 在 org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66) 在 org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:77) 在 org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.lambda$null$2(HierarchicalTestExecutor.java:92)

谢谢。

【问题讨论】:

    标签: java maven easymock junit5


    【解决方案1】:

    在 JUnit 5 中 Rules 不能再使用了。你必须use an Extension 并用ExtendWith 注释测试类或方法。此外,您必须使用@BeforeEach 而不是@Before (See also the migration section in the user guide)。

    更新:自 EasyMock 4.1 起,EasyMock 附带了一个开箱即用的 JUnit 5 extension

    据我所知,目前还没有官方的 EasyMock 扩展。 幸运的是,EasyMockRule 可以很容易地移植:

    import org.easymock.EasyMockSupport;
    import org.junit.jupiter.api.extension.ExtensionContext;
    import org.junit.jupiter.api.extension.TestInstancePostProcessor;
    
    public class EasyMockExtension implements TestInstancePostProcessor {
    
        @Override
        public void postProcessTestInstance(Object testInstance, ExtensionContext context) throws Exception {
            EasyMockSupport.injectMocks(testInstance);
        }
    }
    

    现在你可以注释你的测试类了:

    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.extension.ExtendWith;
    
    // ...
    
    @ExtendWith(EasyMockExtension.class)
    public class BookTest extends EasyMockSupport {
    
        @Mock
        public BookWindow bookWindow;
    
        public BookList bookList;
    
        @TestSubject
        public BookEditor bookEditor;
    
        @BeforeEach
        public void setUp() {
            bookList = new BookList();
            bookEditor = new BookEditor(bookList, bookWindow);
        }
    
        // ...
    

    【讨论】:

      【解决方案2】:

      使用 JUnit Jupiter 的方法

      我认为您的代码的问题之一是它混合使用了 JUnit 4 和 JUnit 5 注释。根据您的堆栈跟踪,我相信您使用的是 JUnit 5 测试引擎,因此您应该将注释 @Before 替换为 @BeforeEach

      我在 JUnit 支持下重现了您的 Eclipse Oxygen 问题。 通过用显式实例化替换基于注释的注入,我通过了NullPointerException

      public class BookTest extends EasyMockSupport {
          public BookWindow bookWindow;
          public BookList bookList;
          public BookEditor bookEditor;
      
          @BeforeEach
          public void setUp() {
              bookWindow = EasyMock.mock(BookWindow.class);
              bookList = new BookList();
              bookEditor = new BookEditor(bookList, bookWindow);
          }
          ...
      }
      

      我没有BookBookListBookEditorBookWindow 的实现,所以我无法验证测试是否通过,但至少它可以运行并且可以定义bookWindow

      使用 JUnit 4 的方法

      话虽如此,我尝试使用 JUnit 4 执行您的代码(将 JUnit Jupiter @Test 注释替换为 @org.junit.Test。这产生了以下异常:

      java.lang.NullPointerException: Have you forgotten to instantiate bookEditor?
      at org.easymock.internal.Injector.injectMocks(Injector.java:81)
      at org.easymock.EasyMockSupport.injectMocks(EasyMockSupport.java:561)
      at org.easymock.internal.EasyMockStatement.evaluate(EasyMockStatement.java:42)
      ...
      

      EasyMock 检查@TestSubject 在注入模拟之前被实例化。我相信您不会希望在 注入模拟之前实例化 BookEditor,因为无论如何您最终都会得到 null bookWindow

      public class BookTest extends EasyMockSupport {
          ...
          @Mock
          public BookWindow bookWindow;
      
          @TestSubject // BookWindow would be null below as not yet injected.
          public BookEditor bookEditor = new BookEditor(bookList, bookWindow);
      

      一种可能性是从bookEditor 实例变量中删除@TestSubject 注释,并在@Before 方法中实例化BookEditor(就像您目前所做的那样):

      public class BookTest extends EasyMockSupport {
          @Rule
          public EasyMockRule rule = new EasyMockRule(this);
      
          @Mock
          public BookWindow bookWindow;
      
          public BookList bookList;
      
          public BookEditor bookEditor;
      
          @Before
          public void setUp() {
              bookList = new BookList();
              bookEditor = new BookEditor(bookList, bookWindow);
          }
          ...
      

      但您可能需要@TestSubject,在这种情况下,此解决方案不可行。

      另一种方法是避免 @Mock 注释并显式实例化模拟:

      public class BookTest extends EasyMockSupport {
          ...
          public BookWindow bookWindow = EasyMock.mock(BookWindow.class);
      
          @TestSubject
          public BookEditor bookEditor = new BookEditor(bookList, bookWindow); 
          ...
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多