在我们的comapny中,我们有一个服务层,它接受一些请求XML,通过JDBC访问各种存储过程(SP),处理数据并使用一些响应XML进行响应。最近人们开始在他们的JUnit测试中采用MockRunner来模拟SP的响应。使用MockRunner设置来自SP的模拟响应的代码看起来很糟糕(这是我打开的第一个随机测试类):
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);
由于许多原因,上面的代码很糟糕,但它确实清楚地显示了从存储过程设置响应的复杂性和开销。
到目前为止,我一直在使用手动滚动依赖注入来注入实际调用存储过程的类。我所要做的就是创建一个模拟SP调用者类(负责SP的实际执行)并设置我想要的响应数据。我对这种技术感到非常满意,并且比上面的数据简单得多,因为它的数据集中而不是担心实现细节。但我的问题是,你什么时候想使用MockRunner?对于单元测试来说,这似乎有些过分,所以我猜它更适合集成或系统测试吗?即便如此,仍然让我更容易使用DI框架交换SP调用者类,然后为每个存储过程调用设置上面的所有代码。请指教!感谢
答案 0 :(得分:3)
最终,你正在研究一般的嘲笑背后的哲学。我会给你两美分,但我也会向你推荐任何一个主要的模拟图书馆,它可能为他们自己的存在提供充分的理由。以Mockito为例。
测试/模拟社区经常区分你手动滚动的东西,通常称为“存根”(静态的,手写的类)和“模拟”(动态的,运行时生成的类)
与仅仅存根相比,模拟的好处相当大。许多测试人员只是为了测试目的而想到了编写接口和/或子类具体类的实现。这样做通常需要实现所述类/接口的所有方法,即使您只是想测试特定方法。
Mocking可以通过定义您想要提供行为的方法来解决这个问题,而且功能强大。此外,模拟允许您将行为从一个测试更改为下一个测试。要使用存根来执行此操作,您必须编写一个全新的存根类。
语法与模拟库有所不同。有些人可能会发现比其他人更具可读性。我目前最喜欢的是Mockito,因此是早期的参考,但它们随着时间的推移而发展。可能值得确定您的组织为何使用模拟套件,以及其他人是否仍然可以满足您的需求以及更具可读性。
希望您的测试编写者将常见行为引入测试设置方法(如JUnit的@Before),这样您就不必一直看到模拟创建和常见初始化。