如何使用 Mockito 关闭存根方法的参数

发布于 2024-10-05 21:14:10 字数 1913 浏览 0 评论 0原文

问候。

我正在嘲笑在我的网络应用程序中测试的搜索引擎。该搜索引擎返回具有不同架构的 xml 文档。该架构取决于称为集合集的参数。基于集合集返回不同的模式是很难模拟的部分,因为指定集合集基本上是一种设置方法,而且是一个无效的方法。这个搜索引擎是一个外部 jar 文件,所以我无法修改 API。我必须按照所提供的内容进行工作。下面是一个示例:

Engine engine = factory.getEngine();
Search search = engine.getSearch();
search.addCollectionSet(someCollectionSet);
SearchResult result = search.getSearchResult();
Document[] documents = result.getAllDocuments();

然后,对于每个文档,我可以通过调用来获取 xml:

document.getDocumentText();

当我使用模拟对象时,getDocumentText() 返回一个由生成器创建的 xml 字符串,该字符串符合架构。我想要做的是使用不同类型的生成器,具体取决于上面第一个代码片段的步骤 3 中提供的集合集。我一直在尝试做这样的事情:

    doAnswer(new Answer() {
        Object answer(InvocationOnMock invocation) {
            if (args == "foo") {
                SearchResult result = getMockSearchResult();
                when(search.getSearchResult()).thenReturn(result);
            }
        }
    }).when(search.addCollectionSet(anyString()));

但这会导致大量红色突出显示:)

基本上,我的目标是关闭 addCollectionSet(someCollectionSet) ,这样当它被调用时,我可以做以某种方式关闭参数并确保使用不同的发生器。有谁知道我怎样才能完成这样的事情?或者是否有某种形式的依赖注入可用于有条件地连接我的生成器?

谢谢!

更新

我已经更改了我的工厂对象,以便它永远不会返回引擎,而是返回该引擎中的搜索和查找对象,所以现在我可以执行如下操作:

Search search = factory.getSearch(collectionSet);

所以我想做的是这样的:

when(factory.getSearch(anyString()).thenAnswer(new Answer() {
    Object answer(InvocationOnMock invocation) {
        switch(args[0]) {
            case fooSet: return fooSearch; break;
            case barSet: return barSearch; break;   

换句话说,我仍然想关闭在 switch 语句中传递给 getSearch 的字符串。诚然,我可以做一些更像菲利克斯下面建议的事情,但我宁愿把所有的箱子都包裹在一个开关中。有人可以举个例子来说明如何做到这一点吗?谢谢!

更新

我发现您可以捕获传递到模拟调用中的参数,但这些捕获的参数用于以后的断言。我还没有找到一种方法可以关闭这些参数,以便对我的模拟的调用将根据参数返回不同的值。似乎必须有一种方法可以做到这一点,我只是没有足够的 Mockito 经验来弄清楚。但肯定有人这么做!

Greetings.

I am mocking a search engine for testing in my web app. This search engine returns xml documents with different schemas. The schema depends on a parameter known as a collection set. Returning different schemas based on collection sets is the part that's difficult to mock, because specifying the collection set is basically a setup method, and a void one at that. This search engine is an external jar file so I can't modify the API. I have to work with what's been provided. Here's an example:

Engine engine = factory.getEngine();
Search search = engine.getSearch();
search.addCollectionSet(someCollectionSet);
SearchResult result = search.getSearchResult();
Document[] documents = result.getAllDocuments();

Then for each document, I can get the xml by calling:

document.getDocumentText();

When I'm using my mock objects, getDocumentText() returns an xml string, created by a generator, that conforms to the schema. What I want to do is use a different type of generator depending on which collection set was provided in step 3 in the first code snippet above. I've been trying to do something like this:

    doAnswer(new Answer() {
        Object answer(InvocationOnMock invocation) {
            if (args == "foo") {
                SearchResult result = getMockSearchResult();
                when(search.getSearchResult()).thenReturn(result);
            }
        }
    }).when(search.addCollectionSet(anyString()));

But this results in lots of red highlighting :)

Basically, my goal is to key off of addCollectionSet(someCollectionSet) so that when it's called, I can do some kind of switch off of the parameter and ensure that a different generator is used. Does anyone know how I can accomplish something like this? Or is there maybe some form of Dependency Injection that could be used to conditionally wire up my generator?

Thanks!

Update

I've changed my factory object so that it never returns the engine, but rather, the Search and Find objects from that engine, so now I can do something like this:

Search search = factory.getSearch(collectionSet);

So what I'd like to do is something like this:

when(factory.getSearch(anyString()).thenAnswer(new Answer() {
    Object answer(InvocationOnMock invocation) {
        switch(args[0]) {
            case fooSet: return fooSearch; break;
            case barSet: return barSearch; break;   

In other words, I still want to key off the string that was passed in to getSearch in a switch statement. Admittedly, I could do something more like felix has suggested below, but I'd rather have all my cases wrapped in a switch. Can someone provide an example of how this could be done? Thanks!

Update

I've seen that you can capture the arguments that are passed into mocked calls, but these captured arguments are used for later assertions. I haven't seen a way that I can key off these arguments so that a call to my mock will return different values depending on the arguments. It seems like there has to be a way to do this, I just don't have enough experience with Mockito to figure it out. But surely someone does!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

魂ガ小子 2024-10-12 21:14:10

我建议将对遗留代码的调用包装到您自己的对象中。
因此,您最终会得到自己的方法:

class SearchEngineWrapper {
  public String getSearchResult(String collection){
    Engine engine = factory.getEngine();
    Search search = engine.getSearch();
    search.addCollectionSet(someCollectionSet);
    SearchResult result = search.getSearchResult();
    ...
    return document.getDocumentText();
  }
}

现在您可以模拟该方法。该方法还很好地记录了您的意图。您还可以在集成测试中测试实际实现。

when(searchEngineWrapper.getSearchResult("abc").thenReturn("foo");
when(searchEngineWrapper.getSearchResult("xyz").thenReturn("bar");

I would recommend wrapping the call to the legacy code into your own object.
So you end up with your own method along these lines:

class SearchEngineWrapper {
  public String getSearchResult(String collection){
    Engine engine = factory.getEngine();
    Search search = engine.getSearch();
    search.addCollectionSet(someCollectionSet);
    SearchResult result = search.getSearchResult();
    ...
    return document.getDocumentText();
  }
}

Now you can mock out this method. The method also nicely documents your intent. Also you could test the actual implementation in an integration test.

when(searchEngineWrapper.getSearchResult("abc").thenReturn("foo");
when(searchEngineWrapper.getSearchResult("xyz").thenReturn("bar");
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文