Java 为什么我要使用MockRunner而不是普通/手动依赖注入?

Java 为什么我要使用MockRunner而不是普通/手动依赖注入?,java,dependency-injection,mockrunner,Java,Dependency Injection,Mockrunner,在我们公司,我们有一个服务层,它接收一些请求XML,通过JDBC访问各种存储过程(SP),处理数据并用一些响应XML进行响应。最近,人们开始在JUnit测试中采用MockRunner来模拟SP的响应。使用MockRunner设置SP的模拟响应的代码看起来很糟糕(这是我打开的第一个随机测试类): 由于许多原因,上面的代码非常糟糕,但它确实清楚地显示了设置存储过程响应的复杂性和开销 到目前为止,我一直在使用手动依赖注入来注入实际调用存储过程的类。我所要做的就是创建一个模拟SP调用者类(负责SP的实际

在我们公司,我们有一个服务层,它接收一些请求XML,通过JDBC访问各种存储过程(SP),处理数据并用一些响应XML进行响应。最近,人们开始在JUnit测试中采用MockRunner来模拟SP的响应。使用MockRunner设置SP的模拟响应的代码看起来很糟糕(这是我打开的第一个随机测试类):

由于许多原因,上面的代码非常糟糕,但它确实清楚地显示了设置存储过程响应的复杂性和开销


到目前为止,我一直在使用手动依赖注入来注入实际调用存储过程的类。我所要做的就是创建一个模拟SP调用者类(负责SP的实际执行)并设置所需的响应数据。我对这种技术非常满意,它比上述技术简单得多,因为它以数据为中心,而不是担心实现细节。但我的问题是,你想什么时候使用MockRunner?对于单元测试来说,这似乎有点过分了,那么我是在猜测它更适合集成还是系统测试呢?即使如此,我仍然觉得使用DI框架交换SP caller类,然后为每个存储过程调用设置上面的所有代码更容易。请开导!谢谢

最终,您将了解嘲笑背后的哲学。我会给你我的两分钱,但我也会向你推荐任何主要的模仿库,这可能会为它们的存在提供很好的理由。比如说

测试/模拟社区通常区分您正在手动进行的操作,通常称为“存根”(一个静态的、手工编写的类)和“模拟”(一个动态的、运行时生成的类)

与简单的存根相比,模仿的好处是相当大的。许多测试人员对仅仅为了测试而编写接口和/或子类具体类的实现的想法感到恼火。要做到这一点,通常需要实现所述类/接口的所有方法,即使您只是想测试特定的方法

Mocking允许您通过定义您想要为其提供行为的方法来绕过这个问题,这非常强大。此外,模拟允许您从一个测试更改行为到下一个测试。要使用存根实现这一点,您必须编写一个全新的存根类

不同的模拟库的语法略有不同。有些你可能会发现比其他人更可读。我目前最喜欢的是Mockito,因此是前面的参考,但它们会随着时间的推移而演变。也许有必要确定您的组织为什么要使用模拟套件,以及另一个是否仍然可以满足您的需求,并且更具可读性


希望您的测试编写人员能够将常见的行为引入测试设置方法(如JUnit的@Before),这样您就不必到处看到模拟创建和常见的初始化。

最终,您将了解模拟背后的基本原理。我会给你我的两分钱,但我也会向你推荐任何主要的模仿库,这可能会为它们的存在提供很好的理由。比如说

测试/模拟社区通常区分您正在手动进行的操作,通常称为“存根”(一个静态的、手工编写的类)和“模拟”(一个动态的、运行时生成的类)

与简单的存根相比,模仿的好处是相当大的。许多测试人员对仅仅为了测试而编写接口和/或子类具体类的实现的想法感到恼火。要做到这一点,通常需要实现所述类/接口的所有方法,即使您只是想测试特定的方法

Mocking允许您通过定义您想要为其提供行为的方法来绕过这个问题,这非常强大。此外,模拟允许您从一个测试更改行为到下一个测试。要使用存根实现这一点,您必须编写一个全新的存根类

不同的模拟库的语法略有不同。有些你可能会发现比其他人更可读。我目前最喜欢的是Mockito,因此是前面的参考,但它们会随着时间的推移而演变。也许有必要确定您的组织为什么要使用模拟套件,以及另一个是否仍然可以满足您的需求,并且更具可读性


希望您的测试编写人员能够将常见行为引入测试设置方法(如JUnit的@Before),这样您就不必到处看到模拟创建和常见初始化了。

谢谢。我很熟悉Mockito,我很喜欢它。谢谢你。我很熟悉Mockito,我很喜欢它。
    MockConnection connection = new MockConnection();
    MockContextFactory.setAsInitial();
    InitialContext context = new InitialContext();
    context.rebind(READ_PAYMENT_DATA_SOURCE, getDS());
    getDS().setupConnection(connection);
    m_csStatementHandler = connection.getCallableStatementResultSetHandler();
    m_csStatementHandler.clearResultSets();
    m_csStatementHandler.clearCallableStatements();
    m_csStatementHandler.setExactMatch(false);
 m_csStatementHandler.prepareReturnsResultSet(READ_PAYMENT, true);
    m_csStatementHandler.setExactMatch(false);
    m_csStatementHandler.setExactMatchParameter(false);
    Map parameterMap = new HashMap();
    parameterMap.put(new Integer(1), null);
    parameterMap.put(new Integer(2), null);
    parameterMap.put(new Integer(3), null);
    parameterMap.put(new Integer(4), null);
    m_csStatementHandler.prepareOutParameter(READ_PAYMENT, parameterMap);
    //Set up the cursor of applications for return.
    MockResultSet resultApps = m_csStatementHandler.createResultSet();  

    resultApps.addRow(getPaymentSchedule("E", "Monthly", new Short("1"),null,null,null,null,null,null,null));
    resultApps.addRow(getPaymentSchedule("A", "Weekly", new Short("1"),null,null,null,null,null,null,null));
    resultApps.addRow(getPaymentSchedule("R", "Yearly", new Short("1"),null,null,null,null,null,null,null));
    resultApps.addRow(getPaymentSchedule("S", "Weekly", new Short("1"),null,null,null,null,null,null,null));
    resultApps.addRow(getPaymentSchedule("W", "Monthly", new Short("1"),null,null,null,null,null,null,null));

    MockResultSet[] results = new MockResultSet[1];
    results[0] = resultApps;
    m_csStatementHandler.prepareResultSet(READ_PAYMENT, resultApps);