Sorry if this comes across as a bunch of disjointed thoughts…I’m just
trying to put my thoughts down and I’d like to know what other people’s
opinions on the subject are.
I’ve been working with Rails for 3 or 4 months now and I’m constantly
trying
to look at ways of improving my testing techniques, especially when it
comes
to TDD. I have a few concerns about the way Rails approaches tests with
regards to controllers/models.
Rails has always seemed to apply that you unit test your models and
functional test your controllers. For me however, this distinction
breaks
down in practice and leads to what are in my opinion very smelly tests.
Firstly, I don’t like the way that by default Rails assumes you want to
test
an entire controller in a testcase. I’ve found that this leads to tests
that
are far to big. I believe better breakdown would be to have a test case
for
each action, or even a testcase for each action in different contexts.
So,
as an example, say you had an ArticleController with view, post and
create
actions. The post action simply displays the form which submits to the
create action.
Now, instead of having one large ArticleControllerTest, it would make
far
more sense to break it down into ArticleViewTest, ArticlePostTest,
FailedArticleCreate test and SuccessfulArticleCreate, because each of
those
represent different contexts, or fixtures.
I’m quite keen on Ben G.’ testing approach outlined
herehttp://www.reevoo.com/blogs/bengriffiths/2005/06/24/a-test-by-any-other-name/and
have also been looking into Dave A.’
RSpec http://rspec.rubyforge.org/ and have to agree with the idea of
testcases being bound by fixtures. If you have test methods that require
common setups, the code should be extracted to the setup method. If you
have
different groups of methods using two different types of setups, this is
an
indication that you should be creating a new testcase for the new
fixture.
Overall, I’ve found that trying to test a whole controller leads to
multiple
fixtures in one testcase and multiple violations of DRY.
This also leads me on to my other concern, and that is the practice of
testing for the presence of markup in a view using assert_tag. I can’t
really see the value in this, and again it seems to violate DRY to me.
Why
would you want to assert that a tag exists in most cases? For example,
given
the ArticlePostTest example above, which wouldn’t really do much in the
controller, and simply pass to the view for the rendering of the form.
Why
would I want to test for the structure of the form? Ultimately my form
will
be laid out using CSS but there are still several ways I could markup my
form, with all variations being “correct”. By testing for one particular
implementation in my test, I’m duplicating the markup in my test and my
view, and binding the test to my implementation of the form. Testing
that a
particular HTML element is present in my view does nothing to tell me
that
my view is “correct”, therefore I think this makes the test worthless.
Which leads me on to saying that views such as forms are the realm for
proper functional testing using something like Watir or Selenium, not
TestUnit and tag assertions. You want to check that you can fill in the
form
and submit it, not that the page contains a tag.
So what would I really like to see? No separation of unit and functional
testing in terms of model and controller code. They should all be
covered by
unit tests. Functional testing should be the realm of something like
Watir
or Selenium, unless somebody can put together a good library that lets
you
do this kind of functional testing (i.e., filling in forms, interacting
with
your web application as if it were in a browser) from within your
TestUnit
tests. I’d like to see less emphasis on the idea of testing your
controllers
as a whole and testing your different actions as smaller, focussed unit
tests. I think this would also aid with TDD.
Dave A.’ has some good reading material here:
http://blog.daveastels.com/?p=53
What do you think?
Cheers
Luke