Skip to content

Chained methods

Let's say you have some code that looks something like the following:

http = HTTP()
results = http.get_url("http://www.google.com").parse().display_results()

You could use flexmock to mock each of these method calls individually:

mock = flexmock(
    get_url=lambda: flexmock(parse=lambda: flexmock(display_results="ok"))
)
flexmock(HTTP).new_instances(mock)

But that looks really error prone and quite difficult to read. Here is a better way:

mock = flexmock()
flexmock(HTTP).new_instances(mock)
mock.should_receive("get_url.parse.display_results").and_return("ok")

When using this short-hand, flexmock will create intermediate objects and expectations, returning the final one in the chain. As a result, any further modifications, such as with_args() or times() modifiers, will only be applied to the final method in the chain. If you need finer grained control, such as specifying specific arguments to an intermediate method, you can always fall back to the above long version.

Word of caution: because flexmock generates temporary intermediate mock objects for each step along the chain, trying to mock two method call chains with the same prefix will not work. That is, doing the following will fail to set up the stub for display_results() because the one for save_results() overrides it:

flexmock(HTTP).should_receive("get_url.parse.display_results").and_return("ok")
flexmock(HTTP).should_receive("get_url.parse.save_results").and_return("ok")

In this situation, you should identify the point where the chain starts to diverge and return a flexmock object that handles all the "tail" methods using the same object:

flexmock(HTTP).should_receive("get_url.parse").and_return(
    flexmock(display_results="ok", save_results="ok")
)