Parameterized extractors

3 views
Skip to first unread message

Eric Lefevre-Ardant

unread,
Nov 29, 2010, 10:33:47 AM11/29/10
to narrati...@googlegroups.com
All,

I have a question on practices regarding extractors. I have 2 ways to access a web page: one with no parameters, one with parameters.

My tests look like this:

public void test1() {
Given...

When.the(quant).attempts_to(open_backtest_results_page());

Then...
}

public void test2() {
Given...

When.the(quant).attempts_to(open_backtest_results_page_for(FTSE));

Then...
}

As you can see, I have 2 'open_backtest_results_page' methods, one with no parameter, one with 1 parameter. However, they still access the same JSP.

I was wondering what others were doing in these cases.
  • Use a single open_backtest_results_page_for(Object) and pass a null to show that there are no parameters (and add an if clause in the extractor)?
  • Write a single method, but with a varargs Object... in parameters?
  • Write 2 methods, with some code duplication in their implementation. Maybe even with slightly differing names, like I did, to ease the reading?
What have you been doing yourselves?

Thanks,

Eric

Douglas Squirrel

unread,
Nov 29, 2010, 4:25:36 PM11/29/10
to narrati...@googlegroups.com

I like either the varargs solution, or the two methods that both read well. In the 2-method solution, you could have one call the other to avoid code duplication.

 

I'd also try to say what the user is trying to accomplish, rather than describing how the UI realises this (what if the UI changes and you're not using pages or JSPs any more?)

 

When.the(quant).attempts_to(view_default_backtest_data());

When.the(quant).attempts_to(view_backtest_data_for(FTSE));

 

Again one of these can call the other to avoid duplication.

Eric Lefevre-Ardant

unread,
Nov 30, 2010, 6:09:37 AM11/30/10
to narrati...@googlegroups.com
In the end, I decided against varargs. I have many variations on the same method, and it gets too confusing to know which parameter is which in a table of Objects.
So, I currently have one extractor per ways of opening the page. That is, almost one per test method (so far). Sounds a lot, but I need to completely convert the 30 test methods in this class to see how much factorization I can get.

I hear your point about abstracting the UI type. Not sure I totally agree as:
  • using web-related words ("page", "open"...) makes it easier for us, developers, to understand what's going on -- we do not have analysts, but I suspect it'd be easier for them too
  • if we were to rework the UI into another paradigm, the refactoring of the signature pales in comparison with the work required to connect to the new UI
But I agree that expressing what the user wants to do makes for a more natural reading.

So far, I end up with the following actions:

When.the(quant).attempts_to(view_backtest_results());
When.the(quant).attempts_to(view_backtest_results_for(FTSE, GBP, Hourly));
When.the(quant).attempts_to(view_backtest_results_for(FTSE, GBP, Hourly, utc(2010, 01, 30), utc(2010, 01, 30)));
When.the(admin).attempts_to(view_backtest_results_for(FTSE, GBP, Hourly, QUANT));

The last line is interesting. What I really want is something like this:
When.the(admin).attempts_to(view_backtest_results_for(FTSE, GBP, Hourly).and_is_using_account(QUANT));
Which seems technically feasible using a builder pattern. Not sure I want actions that are *that* complex, though.

Eric

Douglas Squirrel

unread,
Nov 30, 2010, 6:12:29 AM11/30/10
to narrati...@googlegroups.com

Nice to hear how you are using Narrative, Eric. We do have some examples using builder-type patterns:

    When.the(actor).attempts_to(do_something().with_a(something().called(some_name)));

Happy to share these if that would be of use.

Eric Lefevre-Ardant

unread,
Nov 30, 2010, 6:54:31 AM11/30/10
to narrati...@googlegroups.com
OK, so I had to try myself, then...

I end up with

When.the(quant).attempts_to(view_backtest_results());
When.the(quant).attempts_to(view_backtest_results().with_instrument(FTSE).with_currency(GBP).with_bartype(Hourly));
When.the(admin).attempts_to(view_backtest_results().with_instrument(FTSE).with_currency(GBP).with_bartype(Hourly).with_username(QUANT));
When.the(quant).attempts_to(view_backtest_results().with_instrument(FTSE).with_currency(GBP).with_bartype(Hourly).with_username(QUANT).with_start_date(utc(2010, 01, 30)).with_end_date(utc(2010, 01, 30)));

I don't mind the verbosity too much (although there are other variants in tests that I haven't converted yet), and I like the common view_backtest_results() method. And, especially, it removes some duplication from the old view_backtest_results_with_XXX() methods.
I do find it annoying having to introduce not only a special action builder, but also a method that does nothing but instantiate it. I don't see how I can make it simpler, though.

private ViewBacktestResults view_backtest_results() {
return new ViewBacktestResults();
}

private final class ViewBacktestResults implements Action<Object, Quant> {
@Override
public void performFor(Quant actor) {
String url = ... ; // assemble parameters
actor.tool().logInThenBeginAt(actor.getUserName(), actor.getPassword(), url);
}

// 50 lines of code of with_... methods
}

Ideas to make that simpler:
  • make ViewBacktestResults a public static class. That allows me to statically import the class (import static MyTest.ViewBacktestResults.*), so I can move the view_backtest_results() method in it. Drawback: it makes ViewBacktestResults visible from other classes and also Eclipse won't tell me when I stop referring to that class.
  • instanciate a ViewBacktestResults as a test field. I would then use it like this: When.the(quant).attempts_to(view_backtest_results.with_instrument(FTSE).with_currency(GBP).with_bartype(Hourly)). I don't like the idea of adding more things in the fields, but that might be a good compromise.
Eric

Samir Talwar

unread,
Nov 30, 2010, 7:25:53 AM11/30/10
to narrati...@googlegroups.com
We use public static inner classes with static method constructors. Quite often, we find we can re-use them and move them out into classes of their own.

— Samir.
Reply all
Reply to author
Forward
0 new messages