|
|
|
|
|
|
| |
| |
|
|
From: Orchid Win7 v1
Subject: A curious perversion of the English language
Date: 17 Jul 2013 16:32:31
Message: <51e6ff5f@news.povray.org>
|
|
|
| |
| |
|
|
For the past month and a half, I've been working on performing automated
testing of our product. Now the product *already* has over one thousand
unit tests, which test individual components of the application. But as
any good tester will tell you, you also need integration tests to check
that the pieces actually fit together correctly.
We do have a guy who's job is to test the software. But one human poking
buttons at random to see if anything breaks is far slower and less
systematic than an automated test system. (On the other hand, some tests
cannot be automated - e.g., you can't write a test that checks that the
text is legible, hasn't been cut off the edge of the page, etc.)
In short, I've build a system which allows me to remote-control the
product over the network, and observe its responses. This allows me to
control the software more or less the way a user would - click this
button, select that option, check that the correct data is displayed.
I say "build a system" because, after many, many months of fruitless
Google searching, we discovered that no such system already exists for
our software platform. If it were a web application, there would be
trillions of options for testing tools. If it were written in Qt, we
would have several strong contenders to look at. But it's GTK+, so
there's essentially nothing. We found a couple of OSS tools which were
horribly broken, and that is all.
So I looked at the inner working of one of the tools, and ended up
reimplementing it in C#. And I've spent a month putting all the
functionality we need into it. Essentially I run my server code in the
laptop I want to remote control, and run the client from inside Visual
Studio on my development box. Then I run my test suite, and the tests
talk to the client, which commands the server to do stuff.
Now, originally I wrote all the tests by hand. But more recently I've
started using a curious creation known as SpecFlow. It's a tool for VS
that lets you write user scenarios in "Gherkin", which is "a member of
the Cucumber family of languages". (??!) For those of you who haven't
heard, I will explain further...
Essentially, the idea is that you write a usage scenario in that looks
like free-form English. For example, you might say
Scenario: Adding a new user
Given that I am on the User Admin page
And there is currently no user named 'Tim'
When I press the 'Add User' button
And I type the username 'Tim'
And I type the real name 'Timothy Robinson'
And I press the 'Save' button
Then there should now be a user named 'Tim'
You save this text in a file. You then right-click the file and say "run
tests". The SpecFlow *generates code*, producing an NUnit test fixture -
which is then run. Let me say that again: merely by writing the above
text, a test has been created.
When you run the test, absolutely nothing happens. The test is merely
marked as "inconclusive". Because, hey, the machine has no idea WTF
you're talking about. What you have to do is go write a set of
"bindings", which describe how to transform English into executable code.
If you've been paying attention, you'll have noticed that the above text
isn't *really* free-form English at all. In fact, it's actually pretty
rigidly structured. In fact, the format is line-based. Every line of
text is a "test step". Each such line must begin with "Given", "When" or
"Then". (Or "And", which duplicates the prefix from the previous line.)
The intention is that "Given" lines are test setup, "When" lines are
test actions, and "Then" lines are test assertions. (Although you don't
actually have to follow this, if you're feeling subversive.) What you do
is you write C# code in methods, and you tag the methods with C# method
attributes. For example,
[When("I press the 'Save' button")]
public void PressSave()
{
...actual executable C# code...
}
All SpecFlow actually does is look at each line of English text and then
search the entire VS project (!!) for a method with a matching
annotation. [It appears SpecFlow combines the English text into C# code,
but the actual binding lookups happen at run-time.]
So in this way, all you're really doing is writing the test code
manually, but writing a human-readable summary of what order the code is
run in.
We began by having the testing guy write miles of SpecFlow scenarios,
and then I go through them, press the "generate test steps" button,
which builds a class full of empty step bindings. I then go through each
method and fill it out with real code that really does something. In
this way, the tester guy is like a script writer, and I'm the developer
building the code that implements the tester's vision.
That worked for a while, but then I did what any self-respecting
developer would do - I started to get lazy, and then I started to work
smarter.
Firstly, I figured out that if you edit the test scenarios slightly so
that every test is phrased *exactly* the same way, you can reuse any
test steps you've already implemented. That can save you some coding. So
by making minor grammatical changes to the written English, I could
reduce the amount of code I need to write.
(Lots of scenarios are very similar, to the point that lots of them have
clearly been copy-pasted multiple times. Either that or the guy make the
exact same typo exactly the same way fifteen times in a row...)
Second, I noticed that as I wrote all the code, certain common patterns
of commands popped up again and again. So I wrote a helper class which
allows me to turn these into a single method call. (E.g., I might want
to search for a button with a specific name, check that it's visible,
check that it's enabled, and then click it. That can be made into one
method call.)
That worked for a while. But then I started to get *really* sneaky.
SpecFlow allows you to use regular expressions to actually PARSE STUFF
OUT of test steps. For example,
[When("I press the '(.*)' button")]
public void PressButton(string name)
{
...code...
}
Once I implement the code, I now never, ever have to manually implement
clicking a button again. Suddenly 60% of the test steps I'd been coding
can now share this single step binding. In order words, my work just got
60% easier (and my codebase 60% smaller).
After a while I managed to put together a library of bindings so
comprehensive that for many of the scenarios that had been written, I
could merely reword them very slightly and actually generate an entire,
runnable, valid test WITHOUT WRITING ANY CODE! I could actually build by
test suite just by rephrasing some English into broken robot-speak.
To see how far you can take this, consider the following example:
Scenario: Adding a new user
Given that I am on the User Admin page
And the table does not contain a row with 'Tim' in the 'Username'
column
When I press the 'New User' button
Then I should be on the Create User Page
When I type 'Tim' in the Username field
And I type 'Timothy Robinson' in the Real Name field
And I select the 'Normal User' radio-button
And I check the 'Accounting' check-box
And I press the 'Save' button
Then I should be on the User Admin page
And the table should include the following rows:
| Username | Real Name | Account Type | Group Membership |
| Tim | Timothy Robinson | Normal | Accounting |
That final line has a binding where SpecFlow executes a method with a
"table" as argument. The method actually queries the display, checks
that the specified columns exist in the table, searches for a row where
the Username column contains "Tim", and then checks that the other cells
in that row contain the specified values. This method is *not* specific
to the user admin page; it works for *any* page that has a single table
on it. And it works for any number of rows, and it allows those rows to
appear in any order. (For that matter, the columns may appear in any
order, not necessarily the one shown. And there may be additional
columns that we don't care about.)
In the one hand, this is a fairly crazy level of testing. On the other
hand, this has slowly devolved away from being a high-level user-centric
description of what the application should do, into a very low-level
"check the exact status of every widget on the entire page according to
that I, the application developer, what to test for". Look at the second
line: we've gone from "there isn't a user named Tim" to "the table does
not contain a row with Tim in the Username column".
Maybe I'm doing it wrong.
Eventually, I came across a system of features where the test scenarios
become incredibly repetitive. But SpecFlow has an answer for this also.
Observe:
Scenario: Changing user type from Normal User to Super User
Given that I am on the User Admin page
And the table includes the following rows:
| Username | Account Type |
| Tim | Normal |
When I select the row with 'Tim' in the 'Username' column
And I press the 'Edit' button
Then I should be on the Edit User page
And the 'Username' field should contain 'Tim'
And the 'Normal User' radio-button should be selected
When I select the 'Super User' radio-button
And I press the 'Save' button
Then I should be on the User Admin page
And the table should include the following rows:
| Username | Account Type |
| Tim | SUPER USER |
When I select the row with 'Tim' in the 'Username' column
And I press the 'Edit' button
Then I should be on the Edit User page
And the 'Super User' radio-button should be selected
This checks that when I change the user's type, the data actually saves,
the table updates correctly, and when I recall the data it's still
there. (You'd be surprised how often this fails for obscure properties
that nobody really cares about...)
Now go write a test checking for all the other user types you can
possible have. Yeah, that won't talk long; a few copy-paste operations
later, and this gigantic monstrosity has been duplicated enough that if
you never need to change it, you'll have to change it five times! o_O
So what do I do? I change it to this:
Scenario Outline: Changing user type
Given that I am on the User Admin page
And the table has 'Tim' in the 'Username' column
When I select the row with 'Tim' in the 'Username' column
And I press the 'Edit' button
Then I should be on the Edit User page
And the 'Username' field should contain 'Tim'
When I select the '<type button>' radio-button
And I press the 'Save' button
Then I should be on the User Admin page
And the table should include the following rows:
| Username | Account Type |
| Tim | <type display> |
When I select the row with 'Tim' in the 'Username' column
And I press the 'Edit' button
Then I should be on the Edit User page
And the '<type button>' radio-button should be selected
Examples:
| type button | type name |
| Normal User | Normal |
| Supervisor | Supervisor |
| Manager | Manager |
| Super User | SUPER USER |
We now have a *parametrised* test script. SpecFlow takes my string
template, instantiates it with the data from the table to generate
psuedo-English, with the test bindings then dismantle back into data
which they pass to the server to actually execute the tests. We have now
come completely full circuit and disappeared up our own wotsits!
Look at that final line; SpecFlow replaces by variable with a value,
which the step binding then uses a regex to parse back out so it can
make the server call. (In fairness, you *can* write a template such that
a different method gets called for each instance of the template...)
Look at the vagueness of that parenthetical statement; you can't even
tell which level of templating I'm talking about any more!
Now I am become death, the destroyer of worlds. All we need now is for
SpecFlow to implement conditional branching and iteration, and it'll be
Turing-complete. AND THEN THE WORLD IS NOT SAFE!!
The madness. The madness!!
Post a reply to this message
|
|
| |
| |
|
|
From: Orchid Win7 v1
Subject: Re: A curious perversion of the English language
Date: 17 Jul 2013 16:37:39
Message: <51e70093$1@news.povray.org>
|
|
|
| |
| |
|
|
On 17/07/2013 09:32 PM, Orchid Win7 v1 wrote:
> Now I am become death, the destroyer of worlds. All we need now is for
> SpecFlow to implement conditional branching and iteration, and it'll be
> Turing-complete. AND THEN THE WORLD IS NOT SAFE!!
>
> The madness. The madness!!
...sorry about that. I'm back now.
Post a reply to this message
|
|
| |
| |
|
|
From: Nekar Xenos
Subject: Re: A curious perversion of the English language
Date: 17 Jul 2013 16:50:56
Message: <op.w0dv6517ufxv4h@xena>
|
|
|
| |
| |
|
|
On Wed, 17 Jul 2013 22:37:45 +0200, Orchid Win7 v1 <voi### [at] devnull> wrote:
> On 17/07/2013 09:32 PM, Orchid Win7 v1 wrote:
>> Now I am become death, the destroyer of worlds. All we need now is for
>> SpecFlow to implement conditional branching and iteration, and it'll be
>> Turing-complete. AND THEN THE WORLD IS NOT SAFE!!
>>
>> The madness. The madness!!
>
> ...sorry about that. I'm back now.
Create C+ interface that resembles SpecFlow's language...
.. but that would be a bit redundant.
--
-Nekar Xenos-
Post a reply to this message
|
|
| |
| |
|
|
From: Stephen
Subject: Re: A curious perversion of the English language
Date: 17 Jul 2013 16:56:58
Message: <51e7051a@news.povray.org>
|
|
|
| |
| |
|
|
On 17/07/2013 9:32 PM, Orchid Win7 v1 wrote:
> For the past month and a half, I've been working
[snip]
So, you are enjoying your new job, then?
Admit it. We were right, you were wasted in your old one.
Have you heard how your old workmates are getting on and has your father
found a job yet?
--
Regards
Stephen
Post a reply to this message
|
|
| |
| |
|
|
From: Orchid Win7 v1
Subject: Re: A curious perversion of the English language
Date: 17 Jul 2013 17:20:18
Message: <51e70a92@news.povray.org>
|
|
|
| |
| |
|
|
On 17/07/2013 09:56 PM, Stephen wrote:
> So, you are enjoying your new job, then?
Yeah, at the moment it's OK. Sometimes I wish for a little more
recognition - I just build an entire remote control framework, build a
test framework on top of that, and then built a SpecFlow library on top
of that, in addition to cleaning and implementing over 150 tests. I
doubt anybody else in our office could have made this nice a job of
it... but maybe I'm just deluding myself.
> Admit it. We were right, you were wasted in your old one.
Oh, I thought I admitted that a long time ago. The contention was
whether I *could* get another job, not whether I *should*...
> Have you heard how your old workmates are getting on and has your father
> found a job yet?
My dad has a crap dead-end job that pays peanuts and involves an even
worse commute than the last job. Then again, it beats being unemployed,
so...
Post a reply to this message
|
|
| |
| |
|
|
From: Jim Henderson
Subject: Re: A curious perversion of the English language
Date: 18 Jul 2013 01:08:04
Message: <51e77834@news.povray.org>
|
|
|
| |
| |
|
|
On Wed, 17 Jul 2013 22:20:23 +0100, Orchid Win7 v1 wrote:
> On 17/07/2013 09:56 PM, Stephen wrote:
>> So, you are enjoying your new job, then?
>
> Yeah, at the moment it's OK. Sometimes I wish for a little more
> recognition - I just build an entire remote control framework, build a
> test framework on top of that, and then built a SpecFlow library on top
> of that, in addition to cleaning and implementing over 150 tests. I
> doubt anybody else in our office could have made this nice a job of
> it... but maybe I'm just deluding myself.
I find that particularly in the IT and technical fields, recognition is
difficult. Many managers I've worked for even admitted that they sucked
at it.
I don't think you're deluding yourself - the description you gave of what
you've been working on is something I understand, but I only know a
handful of people who could have done it. Job well done, Andy.
>> Admit it. We were right, you were wasted in your old one.
>
> Oh, I thought I admitted that a long time ago. The contention was
> whether I *could* get another job, not whether I *should*...
You managed it a few weeks after being laid off. It took me 4 months to
find something that is essentially part-time (and 2 years later, I'm
still doing it). I've just applied for a position at a very large
software company, but we'll see how the interview process goes (it's a
large enough company that you don't talk to their "recruiter community",
you have a liaison that you work through for a few weeks. That's a
liaison to the *recruiters*, not to the hiring managers).
Jim
Post a reply to this message
|
|
| |
| |
|
|
From: scott
Subject: Re: A curious perversion of the English language
Date: 18 Jul 2013 03:22:16
Message: <51e797a8@news.povray.org>
|
|
|
| |
| |
|
|
> For the past month and a half, I've been working on performing automated
> testing of our product. Now the product *already* has over one thousand
> unit tests, which test individual components of the application. But as
> any good tester will tell you, you also need integration tests to check
> that the pieces actually fit together correctly.
>
> We do have a guy who's job is to test the software. But one human poking
> buttons at random to see if anything breaks is far slower and less
> systematic than an automated test system. (On the other hand, some tests
> cannot be automated - e.g., you can't write a test that checks that the
> text is legible, hasn't been cut off the edge of the page, etc.)
>
> In short, I've build a system which allows me to remote-control the
> product over the network, and observe its responses. This allows me to
> control the software more or less the way a user would - click this
> button, select that option, check that the correct data is displayed.
>
> I say "build a system" because, after many, many months of fruitless
> Google searching, we discovered that no such system already exists for
> our software platform. If it were a web application, there would be
> trillions of options for testing tools. If it were written in Qt, we
> would have several strong contenders to look at. But it's GTK+, so
> there's essentially nothing. We found a couple of OSS tools which were
> horribly broken, and that is all.
>
> So I looked at the inner working of one of the tools, and ended up
> reimplementing it in C#. And I've spent a month putting all the
> functionality we need into it. Essentially I run my server code in the
> laptop I want to remote control, and run the client from inside Visual
> Studio on my development box. Then I run my test suite, and the tests
> talk to the client, which commands the server to do stuff.
That's obviously totally impossible to actually implement, and there
must be about one person in the entire world whose job it is to do stuff
like that. :-)
Post a reply to this message
|
|
| |
| |
|
|
From: scott
Subject: Re: A curious perversion of the English language
Date: 18 Jul 2013 03:35:17
Message: <51e79ab5@news.povray.org>
|
|
|
| |
| |
|
|
> Now I am become death, the destroyer of worlds. All we need now is for
> SpecFlow to implement conditional branching and iteration, and it'll be
> Turing-complete. AND THEN THE WORLD IS NOT SAFE!!
...unless you reimplemented it all in Haskell :-)
Post a reply to this message
|
|
| |
| |
|
|
From: Orchid Win7 v1
Subject: Re: A curious perversion of the English language
Date: 18 Jul 2013 03:54:01
Message: <51e79f19$1@news.povray.org>
|
|
|
| |
| |
|
|
On 18/07/2013 08:35 AM, scott wrote:
>> Now I am become death, the destroyer of worlds. All we need now is for
>> SpecFlow to implement conditional branching and iteration, and it'll be
>> Turing-complete. AND THEN THE WORLD IS NOT SAFE!!
>
> ...unless you reimplemented it all in Haskell :-)
You laugh, but that's not so implausible. In fact, I posit that the
hardest part would be turning it into a VS plugin... actually parsing
Gherkin and generating code from it should be trivial for just about any
programming language. (Except Bash, because that isn't a real
programming language...)
Post a reply to this message
|
|
| |
| |
|
|
From: Jim Henderson
Subject: Re: A curious perversion of the English language
Date: 18 Jul 2013 15:49:39
Message: <51e846d3$1@news.povray.org>
|
|
|
| |
| |
|
|
On Thu, 18 Jul 2013 08:22:15 +0100, scott wrote:
> That's obviously totally impossible to actually implement, and there
> must be about one person in the entire world whose job it is to do stuff
> like that. :-)
Damn, now I need a new keyboard ;)
Jim
Post a reply to this message
|
|
| |
| |
|
|
|
|
| |
|
|