So on Friday I attended the second barcamb, at the Wellcome Trust Genome Campus. For those not in the know, a barcamp is an unconference. People turn up with stuff to talk about, and a plan for the day is organised over coffee and biscuits at the start of the day.
It was very good interesting day. Many of the faces we saw last year came again, and gave either updates, or new talks, and we had soem new people as well, including a chap who was using the internet to help the Neighbourhood Watch in his village.
Simon Ford brought MBED with him again, showing some more of the exciting stuff he had been doing with it (including something at a 24hr hackathon, which uses a social idea to move packages to their destination).
Unfortunately, I can't remember many peoples names, but is was great to talk with so many of you, and I was rather surprised that my quick unplanned 10minuter on 'It's Too Much Information for ME!' seemed to generate a lot of little discussions with me. It's nice to see that either other people have had the same problem, or that people realise that you end up needing to program for other peoples lack of foresight/rushing development code into production. My talk followed quite nicely from Nava Whiteford's talk on the Swift Analysis pipeline, and Matthew Astleys ad-hoc talk/discussion on Panic Driven Development.
I have some photo's which I have uploaded to Facebook. Please feel free to have a look and tag yourself (or anyone else you know) in any of them.
http://www.facebook.com/photo.php?pid=1183440&l=5b93d&id=665450745
Cheers
Andy
Sunday, 3 August 2008
Friday, 18 July 2008
Perl::Critic - new release
So a new release of Perl::Critic was released, and all I want to say is what a faff.
Some key new features:
1) You must check the return value of all eval statement - don't rely on $EVAL_ERROR/$@
Now, this is a good thing(tm) but it does have some pitfalls, such as where you might be evalling a transactional commit.
eval {
$transaction_state and $dbh->commit();
} or do {
...some 'croak' code
};
The problem here is that the eval isn't a croak if $transaction_state is 0 (as it could be inside a much larger transaction), but the return code would be 0, therefore firing off your 'croak' code.
So, to get round this, you need to return a true value after the statement;
eval {
$transaction_state and $dbh->commit();
1;
} or do {
...some 'croak' code
};
A bit off a faff, but it is better code for it.
2) Declaration of all numbers other than 0,1 and 2
So, as it could be difficult to understand what a number represents when reading the code, you now need to use Readonly to declare any numbers with a named variable at the top of your code.
So now instead of
$percentage = $x * 100/$y;
You need
use Readonly;
Readonly our $PERCENTAGE_MAKER => 100;
...
$percentage = $x * $PERCENTAGE_MAKER/$y;
...
This 'might' make sense to odd numbers floating around, but it also applies to indices on arrays. So if you want the 5th element on an array intstead of requesting
$wanted = $array[4];
You now need
use Readonly;
Readonly our $FIFTH_ARRAY_ELEMENT => 4;
...
$wanted = $array[$FIFTH_ARRAY_ELEMENT];
...
Now, I admit it is often bad to pick out many individual elements from an array by specific number, but it will seriously clutter code where this may be necessary. I admit, for a couple of lines in my code, I have now used ##no critic at the end.
I also wonder why specifically 0,1 and 2 get let off. If the problem is that you don't know if 60 means
i) minutes in an hour
ii) seconds in a minute
iii) degrees in the angle of an equilateral triangle
then 0 could mean off, false, nothing, 0
1 could mean on, true, positive, 1
2 could mean wheels on a bicycle, eyes on a face, hands, 2
Just some examples where I imagine it is because they are the most heavily used for certain features, it would almost impossible to change them (especially 1 as the return value of a perl module)
3) Declaring a variable, which you never (appear to) use
This is annoying if, like me, you use Class::Std to create inside out objects, as you need to declare a hash for your attributes, but this has is never referred to again in the code.
Now, whilst I understand that if you don't use a variable, don't declare it, in this case you are using it, just via the Class::Std methods of the accessors created. However, much like the declaration of numbers, it isn't looking at the context in which you use the declared variable. Again, in this case I have had to wrap these with a ## no critic {} ## use critic in order to not have it fail.
--
So as I said at the beginning, all I want to say is what a faff and the reason is as follows:
We are using Perl::Critic extensively here in New Pipeline Development, and it does force our hand to a Good Coding Practice, but I can't help but wonder here if a couple of these new standards are just a little too overzealous, and causing some things to be overcritised (i.e. a faff).
As with many things, it will take time to get used to programming in advance of critic'ing the code, but I think some of these new features need a little tweaking.
Some key new features:
1) You must check the return value of all eval statement - don't rely on $EVAL_ERROR/$@
Now, this is a good thing(tm) but it does have some pitfalls, such as where you might be evalling a transactional commit.
eval {
$transaction_state and $dbh->commit();
} or do {
...some 'croak' code
};
The problem here is that the eval isn't a croak if $transaction_state is 0 (as it could be inside a much larger transaction), but the return code would be 0, therefore firing off your 'croak' code.
So, to get round this, you need to return a true value after the statement;
eval {
$transaction_state and $dbh->commit();
1;
} or do {
...some 'croak' code
};
A bit off a faff, but it is better code for it.
2) Declaration of all numbers other than 0,1 and 2
So, as it could be difficult to understand what a number represents when reading the code, you now need to use Readonly to declare any numbers with a named variable at the top of your code.
So now instead of
$percentage = $x * 100/$y;
You need
use Readonly;
Readonly our $PERCENTAGE_MAKER => 100;
...
$percentage = $x * $PERCENTAGE_MAKER/$y;
...
This 'might' make sense to odd numbers floating around, but it also applies to indices on arrays. So if you want the 5th element on an array intstead of requesting
$wanted = $array[4];
You now need
use Readonly;
Readonly our $FIFTH_ARRAY_ELEMENT => 4;
...
$wanted = $array[$FIFTH_ARRAY_ELEMENT];
...
Now, I admit it is often bad to pick out many individual elements from an array by specific number, but it will seriously clutter code where this may be necessary. I admit, for a couple of lines in my code, I have now used ##no critic at the end.
I also wonder why specifically 0,1 and 2 get let off. If the problem is that you don't know if 60 means
i) minutes in an hour
ii) seconds in a minute
iii) degrees in the angle of an equilateral triangle
then 0 could mean off, false, nothing, 0
1 could mean on, true, positive, 1
2 could mean wheels on a bicycle, eyes on a face, hands, 2
Just some examples where I imagine it is because they are the most heavily used for certain features, it would almost impossible to change them (especially 1 as the return value of a perl module)
3) Declaring a variable, which you never (appear to) use
This is annoying if, like me, you use Class::Std to create inside out objects, as you need to declare a hash for your attributes, but this has is never referred to again in the code.
Now, whilst I understand that if you don't use a variable, don't declare it, in this case you are using it, just via the Class::Std methods of the accessors created. However, much like the declaration of numbers, it isn't looking at the context in which you use the declared variable. Again, in this case I have had to wrap these with a ## no critic {} ## use critic in order to not have it fail.
--
So as I said at the beginning, all I want to say is what a faff and the reason is as follows:
We are using Perl::Critic extensively here in New Pipeline Development, and it does force our hand to a Good Coding Practice, but I can't help but wonder here if a couple of these new standards are just a little too overzealous, and causing some things to be overcritised (i.e. a faff).
As with many things, it will take time to get used to programming in advance of critic'ing the code, but I think some of these new features need a little tweaking.
Friday, 20 June 2008
Class::Std or Blessed Hash
Objects, Objects, Objects
Everything is objects these days, well, certainly in the world of agile, well structured, extensible, easy to maintain BioInformatics software.
Even Perl6 is aiming to be OO. Probably because of the fact that so many of the modules on CPAN at least expose an OO layer, if not are only OO.
When I started programming PERL, I was writing straight forward top to bottom scripts.
I then moved on to using and producing code in modules, but just exporting the subroutines into the script that used it, for simple code reuse.
Last summer, I got finally taught with hands on development of exactly how OO works and is used. I got a bit confused, but at least I had none of the confusion of
$him = Person->new({args});
$her = $him->new({args});
Which implies a relationship which 'is not there'.
Last summer I discovered Class:Std, which I think is probably my favourite CPAN module of all time. Why?
Well this is the thing. PERL is not an OO language, and it isn't slower because of it. I also learnt Ruby on Rails (as I mentioned in a previous post) and Ruby is slower because everything is an object. Something that clearly sets the two languaged apart.
Now, that isn't the thing that bugs me about OO. In fact, I have learned to embrace PERL OO, and enjoy programming in it. But what does bug me, is that the vast majority of PERL OO breaks encapsulation because all most objects are are HASHes. You have a new constructor, which blesses the package name around a HASH reference. So, when all is said and done, whilst good packages have constructors written to expose the stored data within the object via method calls, you can just access a lot of it via a key.
$him->eye_colour() is equivalent to $him->{eye_colour}
and this encourages lazy programming, because the other advantage is that you can just say 'I need to store some data, what should I do with it, as Person doesn't have an address accessor'
Now, presumably Person does have something that links it to Address. Perhaps Address and Person both have an id_person accessor. But you can cheat. If you want to grab address now, and cache it for later, just do
$person->{address} = $address->house_and_street();
The you can drop the address object, and person now knows exactly where they live.
However, this is dangerous, because
1) Have you deleted something specifically stored in key address
2) What if they move whilst person object is still in memory. You have two places to correct the data.
Why, I hear you cry - I won't do that with my program. No, but someone else will (or you will forget).
Solution use Class::Std;
Class:Std enforces encapsulation. You still get a blessed package, but this time it is a SCALAR, which can't have keys.
You then in each package declare what accessors you want the object to have, and as such enforce people to only use those accessors. You don't have to worry about AUTOLOAD in the history of used modules, as Class::Std handles creating you accessors. You don't even need a new constructor, although you can add a BUILD method which will operate at construction.
So in my example
package Person;
use Class::Std;
{
my %eye_colour_of :ATTR( 'init_arg' => eye_colour, :get<eye_colour>, :set<eye_colour>);
}
1;
my $him = Person->new({eye_colour => 'blue'});
Job done. Less code for initial construction than blessing via new, and you cannot be tempted to throw the address onto the person when it is being used, as
print $him = Person=SCALAR(0x9f2c68)
So, unless you specify in the code (documented and tested, of course) that you want an accessor which allows this object to store the address, it can't be done, and your later code is more robust for it.
Now, where am I going with all of this?
Well, I use Clearpress to form a base for my PERL web apps in my current role. It is a good solid platform which I have mentioned before, and I am very happy to work within it. However, I am writing an API to use the services it provides. Clearpress doesn't use Class::Std. My API does. This is no problem as they talk via LWP::UserAgent requests, but it is quite confusing as the live in the same project in subversion. And my big thing is that I am programming both at the same time. This is bad news, as I have been trying to use features of one type of Object with the other. It hasn't really made a significant difference, as the package name reminds me which I should be using, but is is wierd getting the error when you try to cheat, and use a key to cache some info in the Class::Std object, as it is a scalar.
So, from this, I am going to finish the project in the way I have started it, but I think from now on there is one golden rule:
Use only one type of object, and just ensure you enforce encapsulation by the way you program - don't get lazy.
Now, to convince my boss to refactor Clearpress into Class::Std...
Everything is objects these days, well, certainly in the world of agile, well structured, extensible, easy to maintain BioInformatics software.
Even Perl6 is aiming to be OO. Probably because of the fact that so many of the modules on CPAN at least expose an OO layer, if not are only OO.
When I started programming PERL, I was writing straight forward top to bottom scripts.
I then moved on to using and producing code in modules, but just exporting the subroutines into the script that used it, for simple code reuse.
Last summer, I got finally taught with hands on development of exactly how OO works and is used. I got a bit confused, but at least I had none of the confusion of
$him = Person->new({args});
$her = $him->new({args});
Which implies a relationship which 'is not there'.
Last summer I discovered Class:Std, which I think is probably my favourite CPAN module of all time. Why?
Well this is the thing. PERL is not an OO language, and it isn't slower because of it. I also learnt Ruby on Rails (as I mentioned in a previous post) and Ruby is slower because everything is an object. Something that clearly sets the two languaged apart.
Now, that isn't the thing that bugs me about OO. In fact, I have learned to embrace PERL OO, and enjoy programming in it. But what does bug me, is that the vast majority of PERL OO breaks encapsulation because all most objects are are HASHes. You have a new constructor, which blesses the package name around a HASH reference. So, when all is said and done, whilst good packages have constructors written to expose the stored data within the object via method calls, you can just access a lot of it via a key.
$him->eye_colour() is equivalent to $him->{eye_colour}
and this encourages lazy programming, because the other advantage is that you can just say 'I need to store some data, what should I do with it, as Person doesn't have an address accessor'
Now, presumably Person does have something that links it to Address. Perhaps Address and Person both have an id_person accessor. But you can cheat. If you want to grab address now, and cache it for later, just do
$person->{address} = $address->house_and_street();
The you can drop the address object, and person now knows exactly where they live.
However, this is dangerous, because
1) Have you deleted something specifically stored in key address
2) What if they move whilst person object is still in memory. You have two places to correct the data.
Why, I hear you cry - I won't do that with my program. No, but someone else will (or you will forget).
Solution use Class::Std;
Class:Std enforces encapsulation. You still get a blessed package, but this time it is a SCALAR, which can't have keys.
You then in each package declare what accessors you want the object to have, and as such enforce people to only use those accessors. You don't have to worry about AUTOLOAD in the history of used modules, as Class::Std handles creating you accessors. You don't even need a new constructor, although you can add a BUILD method which will operate at construction.
So in my example
package Person;
use Class::Std;
{
my %eye_colour_of :ATTR( 'init_arg' => eye_colour, :get<eye_colour>, :set<eye_colour>);
}
1;
my $him = Person->new({eye_colour => 'blue'});
Job done. Less code for initial construction than blessing via new, and you cannot be tempted to throw the address onto the person when it is being used, as
print $him = Person=SCALAR(0x9f2c68)
So, unless you specify in the code (documented and tested, of course) that you want an accessor which allows this object to store the address, it can't be done, and your later code is more robust for it.
Now, where am I going with all of this?
Well, I use Clearpress to form a base for my PERL web apps in my current role. It is a good solid platform which I have mentioned before, and I am very happy to work within it. However, I am writing an API to use the services it provides. Clearpress doesn't use Class::Std. My API does. This is no problem as they talk via LWP::UserAgent requests, but it is quite confusing as the live in the same project in subversion. And my big thing is that I am programming both at the same time. This is bad news, as I have been trying to use features of one type of Object with the other. It hasn't really made a significant difference, as the package name reminds me which I should be using, but is is wierd getting the error when you try to cheat, and use a key to cache some info in the Class::Std object, as it is a scalar.
So, from this, I am going to finish the project in the way I have started it, but I think from now on there is one golden rule:
Use only one type of object, and just ensure you enforce encapsulation by the way you program - don't get lazy.
Now, to convince my boss to refactor Clearpress into Class::Std...
Wednesday, 7 May 2008
To scroll within or out
So an interesting thing arose out of my work recently, both NPG and a personal project, which is how to scroll tables.
In NPG, we have many tables of data, from run information, to search results, to instrument information. These are generated from templates and render to the browser.
In V:YaDB, I have the same issue, as well in excess of 2000 cards is quite a bit to scroll through, but again it is templated.
Following good practice and webstandards, we are all using
<table>
<thead>
.
.
</thead>
<tfoot>
.
.
</tfoot>
<tbody>
.
.
.
.
</tbody>
</table>
or at least we should be. Most modern browsers insert this anyway, but putting it in gives you some additional css tags, and ensures you and future developers of your project know what is going where (and for anyone not familiar with this, <tfoot> should be before <tbody>, although it is optional to have a footer to your table).
Anyway, with this in mind, it should be easy to just put the following css in to make the body part of your table scroll, therefore leaving the head fixed, to keep column header visible
tbody {height:300px;overflow:auto;overflow-x:hidden;}
However, this only works in the firefox browser. What is going on there? But it is true. I spent some time this weekend on IE7 and Safari and found this to be true.
So, back to square one. Searching google found a lot of real hacks, from serious amounts of Javascript, to running different css files dependent on browser (including separate versions for IE6 and IE7). Madness.
One idea I came across that I liked the most though was the idea of two table renders. Whilst this means it is only really suitable for quick to render tables, this is something that is possible.
Now, there are two options here.
1) Using declared fixed width columns, produce one table which only has the thead part of your table. Then immediately beneath it produce the table with the data in. This one could be a bigger table because it only has to render data once, but you have no flexibility should you need to add a new column of data.
2) In a fixed height div, render two copies of the table using absolute positioning over each other. Then wrap each in it's own div labelled with an id. Using using z-align:1; for the one you want to scroll, and z-align:2; for the head, and fix the height of the head div to that only the head row is shown, and set overflow:hidden; Set the height of the scroll table to the height of the outer div, and set overflow:auto; overflow-x:hidden;
(with 2, obviously, you could also fix the width, and for both show the overflow-x)
Also with both, you need to declare a spacer column, which will then ensure room for your scrollbar.
I personally prefer 2, which I managed to create some css to produce a nice effect with the fact that with 2 tables, I was able to manipulate the header style without needing to worry about if it affected the rest of the data, and also revealed the bottom border only to give a ruled effect.
The downside to 2 is that anyone with css turned off will end up viewing two copies of your table, but hey, no-one should be turning off css or javascript in their browsers, and if you know someone who does, 'send the boyz round to ave a wurd'.
I think that I am going to expand scrumptious to have javascript and css effects, and this will be the first css effect in it. I'll let you know when the sourceforge svn trunk is updated.
However, start lobbying your local MP today to get the simplest option put into your favourite browser, or if your fave is already firefox/iceweasel, then at least IE and Safari.
Please note: I have nothing against Opera, Camino or any other browsers out there, I just don't use them on a regular basis.
In NPG, we have many tables of data, from run information, to search results, to instrument information. These are generated from templates and render to the browser.
In V:YaDB, I have the same issue, as well in excess of 2000 cards is quite a bit to scroll through, but again it is templated.
Following good practice and webstandards, we are all using
<table>
<thead>
.
.
</thead>
<tfoot>
.
.
</tfoot>
<tbody>
.
.
.
.
</tbody>
</table>
or at least we should be. Most modern browsers insert this anyway, but putting it in gives you some additional css tags, and ensures you and future developers of your project know what is going where (and for anyone not familiar with this, <tfoot> should be before <tbody>, although it is optional to have a footer to your table).
Anyway, with this in mind, it should be easy to just put the following css in to make the body part of your table scroll, therefore leaving the head fixed, to keep column header visible
tbody {height:300px;overflow:auto;overflow-x:hidden;}
However, this only works in the firefox browser. What is going on there? But it is true. I spent some time this weekend on IE7 and Safari and found this to be true.
So, back to square one. Searching google found a lot of real hacks, from serious amounts of Javascript, to running different css files dependent on browser (including separate versions for IE6 and IE7). Madness.
One idea I came across that I liked the most though was the idea of two table renders. Whilst this means it is only really suitable for quick to render tables, this is something that is possible.
Now, there are two options here.
1) Using declared fixed width columns, produce one table which only has the thead part of your table. Then immediately beneath it produce the table with the data in. This one could be a bigger table because it only has to render data once, but you have no flexibility should you need to add a new column of data.
2) In a fixed height div, render two copies of the table using absolute positioning over each other. Then wrap each in it's own div labelled with an id. Using using z-align:1; for the one you want to scroll, and z-align:2; for the head, and fix the height of the head div to that only the head row is shown, and set overflow:hidden; Set the height of the scroll table to the height of the outer div, and set overflow:auto; overflow-x:hidden;
(with 2, obviously, you could also fix the width, and for both show the overflow-x)
Also with both, you need to declare a spacer column, which will then ensure room for your scrollbar.
I personally prefer 2, which I managed to create some css to produce a nice effect with the fact that with 2 tables, I was able to manipulate the header style without needing to worry about if it affected the rest of the data, and also revealed the bottom border only to give a ruled effect.
The downside to 2 is that anyone with css turned off will end up viewing two copies of your table, but hey, no-one should be turning off css or javascript in their browsers, and if you know someone who does, 'send the boyz round to ave a wurd'.
I think that I am going to expand scrumptious to have javascript and css effects, and this will be the first css effect in it. I'll let you know when the sourceforge svn trunk is updated.
However, start lobbying your local MP today to get the simplest option put into your favourite browser, or if your fave is already firefox/iceweasel, then at least IE and Safari.
Please note: I have nothing against Opera, Camino or any other browsers out there, I just don't use them on a regular basis.
Wednesday, 30 April 2008
History Meme
So I got tagged to do this by my boss Roger, and a lot of my work colleagues are doing it. So here is the result from my macbook:
history|awk '{print $2}'|sort|uniq -c|sort -rn|head
167 prove
62 cd
55 svn
45 cover
42 ls
32 rake
28 mate
11 make
8 ./bin/apachectl
7 sudo
So I am testing quite a lot on my machine (prove and cover) (always trying for test driven development is the reason for this). cd is obvious. svn is vitally important.
I am surprised rake turns up more than make though
More service soon.
Andy
history|awk '{print $2}'|sort|uniq -c|sort -rn|head
167 prove
62 cd
55 svn
45 cover
42 ls
32 rake
28 mate
11 make
8 ./bin/apachectl
7 sudo
So I am testing quite a lot on my machine (prove and cover) (always trying for test driven development is the reason for this). cd is obvious. svn is vitally important.
I am surprised rake turns up more than make though
More service soon.
Andy
Monday, 7 April 2008
Javascript for all
So on Friday, as a gentle way of trying to get back into work mode after the Rails course had finished, I started
by trying to refactor out a lot of javascript from the templates.
I have just bought 'Pragmatic Ajax (A Web 2.0 Primer)' from The Pragmatic Programmers. It is a very interesting read, and
inspired me to 'get the code out of the view'
It's true to say, that we have been quite lax in simply putting <script> tags in with fairly specialised javascript
functions, which don't really need any variables passed to them (as the function ends up with the paths and div ids hard=coded).
Well, I managed to refactor out most of the functions that we had written, and with a few additions to variables being passed to them, managed to reduce the number of some function (or make them more genericised for future reference). I even discovered a slight problem with my scrumptious.js which I need to tweak and document.
The great thing is that we have now reduced the code in the views. This makes the views easier to read and keep upto date.
There are still a few functions which I should be able to refactor, but I need to find out a couple of extra things first.
I've only got through the first 3 chapters of 'Pragmatic Ajax' so far, but it has explained a bit that so far I hadn't known from just my experience learning some Ajax through RoRails. Chapter 1 explains about what Ajax is, Chapter 2 shows you how to develop Ajaxian Maps (a google maps clone). Then it has started to go into the Nitty Gritty details of Ajax and Client-side Javascript.
However, so far the javascript examples have all been written in the html head, rather than in a separate .js file. I imagine (hope) that this will change in a best practice suggestion. I'm also hoping it will show a bit on testing javascript, which so far is something that I haven't done.
My experience of programming books has led me to find the Pragmatic Programmers books are a great way of finding the information in an easy to read style. So far, Pragmatic Ajax is a good book and hasn't let me down in it's style and (most importantly) content.
by trying to refactor out a lot of javascript from the templates.
I have just bought 'Pragmatic Ajax (A Web 2.0 Primer)' from The Pragmatic Programmers. It is a very interesting read, and
inspired me to 'get the code out of the view'
It's true to say, that we have been quite lax in simply putting <script> tags in with fairly specialised javascript
functions, which don't really need any variables passed to them (as the function ends up with the paths and div ids hard=coded).
Well, I managed to refactor out most of the functions that we had written, and with a few additions to variables being passed to them, managed to reduce the number of some function (or make them more genericised for future reference). I even discovered a slight problem with my scrumptious.js which I need to tweak and document.
The great thing is that we have now reduced the code in the views. This makes the views easier to read and keep upto date.
There are still a few functions which I should be able to refactor, but I need to find out a couple of extra things first.
I've only got through the first 3 chapters of 'Pragmatic Ajax' so far, but it has explained a bit that so far I hadn't known from just my experience learning some Ajax through RoRails. Chapter 1 explains about what Ajax is, Chapter 2 shows you how to develop Ajaxian Maps (a google maps clone). Then it has started to go into the Nitty Gritty details of Ajax and Client-side Javascript.
However, so far the javascript examples have all been written in the html head, rather than in a separate .js file. I imagine (hope) that this will change in a best practice suggestion. I'm also hoping it will show a bit on testing javascript, which so far is something that I haven't done.
My experience of programming books has led me to find the Pragmatic Programmers books are a great way of finding the information in an easy to read style. So far, Pragmatic Ajax is a good book and hasn't let me down in it's style and (most importantly) content.
Thursday, 3 April 2008
Advancing with Rails course - Day 4 pt 3
So, the final bit of the course has been looking at integration testing
objective is to go through the processes to a conclusion, i.e.
login >>
attempt to bid on an auction you started >>
fail
login >>
bid on auction as highest bidder >>
fail
login >>
bid on auction >>
pass
and so on
can cross controllers which is why next level up from functional tests. May be more than one/two asserts as
they are linked and this is useful to ensure it doesn't bother trying tests it can't even get to
very good place to often refactor heavily
integration testing routes
def test_show_route
assert_recognizes({:controller => :auctions,
:action => :show,
:id => "1"}, auction_path(1)) <==named routes
end
def test_generate_route
assert_generates("/auctions/3", :controller => :auctions,
:action => :show,
:id => "3")
end
also can assert_routes
you could get back responses to look at when rjs is rendered
irb>> app.get("/auctions/destroy/1")
>> 200
irb>> app.response.body
(output of rjs file)
rcov tool
coverage of code with tests
ZenTest
runs in another terminal window, and everytime you make and save a change to a file, it works out the tests which are affected and reruns those tests.
objective is to go through the processes to a conclusion, i.e.
login >>
attempt to bid on an auction you started >>
fail
login >>
bid on auction as highest bidder >>
fail
login >>
bid on auction >>
pass
and so on
can cross controllers which is why next level up from functional tests. May be more than one/two asserts as
they are linked and this is useful to ensure it doesn't bother trying tests it can't even get to
very good place to often refactor heavily
integration testing routes
def test_show_route
assert_recognizes({:controller => :auctions,
:action => :show,
:id => "1"}, auction_path(1)) <==named routes
end
def test_generate_route
assert_generates("/auctions/3", :controller => :auctions,
:action => :show,
:id => "3")
end
also can assert_routes
you could get back responses to look at when rjs is rendered
irb>> app.get("/auctions/destroy/1")
>> 200
irb>> app.response.body
(output of rjs file)
rcov tool
coverage of code with tests
ZenTest
runs in another terminal window, and everytime you make and save a change to a file, it works out the tests which are affected and reruns those tests.
Subscribe to:
Posts (Atom)