【问题标题】:Mocking a class that Verticle depends on模拟 Verticle 依赖的类
【发布时间】:2015-12-21 09:29:12
【问题描述】:

我正在使用 Vert.x 3 框架/库。 我编写了一个简单的 Verticle,它具有通过 Spring IoC 管理的对象依赖项。

这里是 Verticle sn-p

public class BookmarksVerticle extends AbstractVerticle {
    private static Logger log = LoggerFactory.getLogger(BookmarksVerticle.class);

    @Resource
    private BookmarkDao bookmarksDao;

这里是Spring配置sn-p

@Bean 
public BookmarkDao bookmarksDao() {
    ...
}
@Bean 
public BookmarksVerticle bookmarkVerticle() {
     return new BookmarksVerticle();
}   

这一切都很好。所以想写一些测试。 我正在使用 vertx-unit 测试并试图模拟 DAO

这就是我所拥有的

@RunWith(VertxUnitRunner.class)
public class BookmarksVerticleTest {

    int port = 8888;
    private Vertx vertx;

    @Mock(name = "BookmarkDao")
    BookmarkDao mockDao;
    @InjectMocks
    BookmarksVerticle bmVerticle;

    @Before
    public void init(TestContext context) {
        MockitoAnnotations.initMocks(this);

        vertx = Vertx.vertx();
        DeploymentOptions options = new DeploymentOptions().setConfig(new JsonObject().put("http.port", port));
        vertx.deployVerticle(bmVerticle, options, context.asyncAssertSuccess());
    }

但是,当我运行测试时,我得到了 NPE

SEVERE: NULL
java.lang.NullPointerException
    at vertx.pragprog.bookmarks.BookmarksVerticle.asynchRetrieveBookmark(BookmarksVerticle.java:169)
    at vertx.pragprog.bookmarks.BookmarksVerticle.lambda$1(BookmarksVerticle.java:88)
    at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$14(ContextImpl.java:279)
    at io.vertx.core.impl.OrderedExecutorFactory$OrderedExecutor.lambda$new$161(OrderedExecutorFactory.java:91)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

触发异常的行是我访问 DAO 的地方

        Bookmark bm = bookmarksDao.getBookmark(id);

mockDao 没有被注入 Verticle。

关于为什么会出现这种情况的任何想法?

更新:

尝试通过为BookmarksVerticle上的DAO添加setter方法来删除Mockito自动创建类,然后将单元测试中的setup方法更改如下:

@Before
public void setUp(TestContext context) {    
    log.info("setting up...");
    //MockitoAnnotations.initMocks(this);

    mockDao = mock(BookmarkDao.class);
    bmVerticle = new BookmarksVerticle();
    bmVerticle.setBookmarkDao(mockDao);

    vertx = Vertx.vertx();
    DeploymentOptions options = new DeploymentOptions().setConfig(new JsonObject().put("http.port", port));
    vertx.deployVerticle(bmVerticle, options, context.asyncAssertSuccess());
}

即使采用这种方法,我仍然会遇到 NPE

更新 2

我通过测试BookmarksVerticle 上的一个方法从组合中删除了vertx 和VertxUnitRunner,该方法对vertx 没有任何依赖,但使用了DAO 类。

public class BookmarksServiceTest {

    @Mock(name = "BookmarkDao")
    BookmarkDao mockDao;
    @InjectMocks
    BookmarksVerticle bmVerticle;

    @Before
    public void setUp() {   
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void test_retrieveBookmark() {
        String id = "1";
        when(mockDao.getBookmark(Matchers.anyString())).thenReturn(new Bookmark(id, "url", "Vert.x"));

        Bookmark bm = bmVerticle.retrieveBookmark(id);
        assertNotNull(bm);
        assertEquals(id, bm.getBookmarkId());
        assertEquals("Vert.x", bm.getBookmarkTitle());
    }

}

这很好用!似乎VertxUnitRunner 可能会以某种方式干扰 Mockito。

谢谢

【问题讨论】:

  • 看起来 mockDao 没有被注入 bmVerticle。尝试从 @Mock 中删除 name 属性或尝试 @Mock(name = "bookmarksDao")
  • 谢谢,但我都试过了,但也没有用。我只是不确定为什么 mockDao 没有被注入。我之前用过几次,只是没有用 Vert.x
  • 除此之外,我添加的日志记录(JUL 和 log4j)都不起作用。后者似乎是 b/c 它找不到 log4j.xml 但那是在类路径中
  • 不确定是否需要 MockitoAnnotations.initMocks(this);当你有@RunWith(VertxUnitRunner.class)。
  • 如果我不调用 initMocks 那么什么会模拟 DAO 并将其注入 Verticle?

标签: java unit-testing mockito vert.x


【解决方案1】:

好消息是 Mockito 与 VertxUnitRunner 合作! 事实证明,在命令行上使用 Maven,而 Eclipse 把我弄乱了。一旦我切换出嵌入式 maven 以使用与我在命令行中使用的相同的 maven 安装,事情就开始工作了。

以下是另一个答案的详细信息: Successful build in Maven still showing errors in Eclipse

【讨论】:

【解决方案2】:

BookmarksVerticle 有非默认构造函数吗?

@InjectMocks 的文档指出在这种情况下不会发生字段注入。

请看这里:http://docs.mockito.googlecode.com/hg/1.9.5/org/mockito/InjectMocks.html

【讨论】:

  • BookmarksVerticle 只有默认构造函数。谢谢。
  • 当一切都失败时,摆脱魔法。尝试直接使用new 手动创建BookmarksVerticle。为 Spring 保留一个受保护的默认构造函数(以便自动装配工作)并创建一个单独的公共构造函数,采用 BookmarksDao,以便您可以直接将其传递给测试。
  • 我为 DAO 添加了一个 setter 方法,并按照建议消除了模拟注入。请参阅 OP 中的更新。
  • 既然你添加了一个setter,这里有一些尝试——将Spring @Resource 注解从字段移动到你的setter 方法。如果 Spring 在图片中,那将导致 Spring 使用方法而不是反射来设置 BookmarksDao 值。然后将调试器放在 setter 上,看看会发生什么。
  • 好主意。但是,不确定这是否重要,因为我没有在单元测试中使用 Spring。我确实从混合中删除了 Vertx,它 Mockito 在注入 mockDao 时工作(参见更新 2)。但是,到目前为止,我仍然无法测试 Verticle 部件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-02-27
  • 1970-01-01
  • 2021-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多