简体   繁体   English

为什么在常规/手动滚动依赖项注入上使用MockRunner?

[英]Why would I use MockRunner over normal/hand rolled dependency injection?

At our comapny, we have a service layer which takes in a some request XML, accesses various Stored Procecdures (SP's) via JDBC, processes the data and responds with some response XML. 在我们的公司,我们有一个服务层,该服务层接收一些请求XML,通过JDBC访问各种存储过程(SP),处理数据并以一些响应XML进行响应。 Lately people have begun to adopt MockRunner in their JUnit tests to mock the responses from the SP's. 最近人们开始在其JUnit测试中采用MockRunner来模拟SP的响应。 The code to setup the mocked responses from the SP's using MockRunner looks awful (this is the first random test class I opened): 使用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);   

The code above is awful for many reasons, but it does clearly show the complexity and overhead of setting up a response from the stored procedures. 上面的代码有很多原因,但是很糟糕,但确实显示了从存储过程中建立响应的复杂性和开销。

To date I have been using hand rolled dependency injection instead to inject the class that actually calls the Stored Procedure. 迄今为止,我一直在使用手动滚动依赖项注入来注入实际调用存储过程的类。 All I have to do is create a mock SP caller class (responsible for the actual execution of the SP) and set my desired response data. 我要做的就是创建一个模拟SP调用程序类(负责SP的实际执行)并设置所需的响应数据。 I'm very happy with this technique and its much simplier than the above as its data focused rather than worrying about implementation details. 我对这种技术及其比上面的方法简单得多感到非常满意,因为它的数据集中于而不是担心实现细节。 But my question is, when would you want to use MockRunner? 但是我的问题是,您什么时候要使用MockRunner? It seems overkill for unit tests, so am I guessing its more for integration or system testing? 对于单元测试来说似乎有些大材小用,所以我是否认为它对集成或系统测试的影响更大? And even then, it still strikes me as easier to use a DI framework to swap out the SP caller class then to setup all the code above for every stored procedure call. 即便如此,使用DI框架换出SP调用程序类,然后为每个存储过程调用设置以上所有代码,仍然让我感到更轻松。 Please enlighten! 请赐教! Thanks 谢谢

Ultimately you're looking into the philosophy behind mocking in general. 最终,您正在研究一般模拟背后的哲学。 I'll give you my two cents, but I'd also refer to you any major mocking library, which is likely to provide good justification for their own existence. 我将给您我的两分钱,但我还要提及您任何主要的模拟库,这很可能为它们的存在提供充分的理由。 Take Mockito , for example. Mockito为例。

The testing/mocking community often distinguishes between what you're hand-rolling, which is usually called a "stub" (a static, hand-written class) versus a "mock" (a dynamic, runtime-generated class). 测试/模拟社区经常区分手动滚动(通常称为“存根”(静态,手写类))和“模拟”(动态,运行时生成的类)之间的区别。

The benefits of mocking are pretty big in comparison to just stubbing. 与仅存根相比,嘲笑的好处非常大。 Many testers chafe at the idea of going off to write implementations of interfaces and/or subclass concrete classes just for the purpose of testing. 许多测试人员对仅出于测试目的而编写接口和/或子类具体类的实现的想法感到不满。 To do so often requires the implementation of ALL methods of said class/interface, even when you just want to test a specific method. 这样做通常需要实现所述类/接口的所有方法,即使您只是想测试特定的方法。

Mocking lets you get around that problem by defining just the methods to which you want to give behavior, and that's powerful. 通过模拟,您只需定义要赋予其行为的方法即可解决该问题,并且功能强大。 In addition, mocking allows you to change behavior from one test to the next. 另外,通过模拟,您可以将行为从一项测试更改为另一项测试。 To do that with stubbing, you'd have to write an entirely new stub class. 要实现存根,您必须编写一个全新的存根类。

The syntax varies a little from mocking library to library. 语法因模拟库而异。 Some you may find more readable than others. 您可能会发现其中一些比其他一些更具可读性。 My current favorite is Mockito, hence the earlier reference, but they evolve over time. 我目前最喜欢的是Mockito,因此是较早的参考书,但是随着时间的推移它们会不断发展。 It might be worth determining why your organization is using the mocking suite that it is and whether another might still meet your needs as well as being more readable. 可能值得确定您的组织为何使用它原来的模拟套件,以及另一个组织是否仍然可以满足您的需求以及更具可读性。

Hopefully your test-writers are pulling common behavior into test-setup methods (like JUnit's @Before) so you don't have to keep seeing mock-creation and common initialization all over the place. 希望您的测试编写者将常见的行为引入到测试设置方法中(例如JUnit的@Before),这样您就不必一直在各处看到模拟创建和通用初始化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM