Showing posts with label tdd. Show all posts
Showing posts with label tdd. Show all posts
Thursday, April 4, 2013
Three tales of browser-based test suites [Part 2] - test harder
Labels:
javascript,
maven,
selenium,
tdd
In Part 1 I wrote about my initial experience testing with Selenium. In this part I will write about what I learned about browser-based tests on my first project working for ThoughtWorks. It was a step up in terms of coverage and complexity and that also brought its own set of problems.
Tuesday, July 31, 2012
Three tales of browser-based test suites [Part 1]
Labels:
java,
javascript,
selenium,
tdd
The topic of browser-based testing seems to come up again and again and on many occasions I meet people who have expectations that don't match my experience. So I guess it only makes sense to write down these experiences and some of the conclusions I came to.
I'm not even going to try and go into distinctions between acceptance, functional, integration or whatever testing. Whatever you're calling those tests, if they are instrumenting a web browser, that's what I'm talking about. (If you care about the distinctions, or about testing in general, I recommend reading Gojko Adzic's excellent book Specification By Example.)
I want to look at three concrete examples that I have worked on over the past years.
In the first case, nobody on our team had prior experience, except for a short but traumatic brush with IBM's Rational Functional Tester (remember kids: friends don't let friends use IBM products). To get rid of that, we decided to go ahead and try Selenium.
We initially recorded tests with the Firefox plugin but quickly realized that this wasn't maintainable and didn't really offer us good control for selecting elements. Our Tester Benjamin then took it upon him to write tests in Java and started to integrate them into our CI environment. Over time he created a solid set of Page Objects that allowed us to write new tests fairly quickly.
It took the rest of the team quite a while to take some ownership of these tests but eventually we came to a point where we'd sometimes even drive new features from these Selenium Tests.
There were hurdles along the way. Tests were brittle and the execution time was unacceptable (>30 mins). This improved with newer versions of Selenium, use of Selenium Grid to parallelize tests and by keeping a close eye on the VMs running the browser instances. In the case of IE(<8 gave="gave" just="just" p="p" simply="simply" up.="up." we="we">
Due to some relatively complex processes it was also fairly hard to test later stages of these processes. We only slowly got better at setting up test data for this without making use of the browser. This left us with some unfortunate holes in automated coverage.
There were still manual tests for each release for all of our major supported browsers. But with more of the core functionality being handled by automated tests and with the amount of changes shrinking due to shorter release cycles the effort for this went down considerably.
We also became better at writing unit and integration tests and our confidence in these grew.
What did I take away from it:
8>
I'm not even going to try and go into distinctions between acceptance, functional, integration or whatever testing. Whatever you're calling those tests, if they are instrumenting a web browser, that's what I'm talking about. (If you care about the distinctions, or about testing in general, I recommend reading Gojko Adzic's excellent book Specification By Example.)
I want to look at three concrete examples that I have worked on over the past years.
In the first case, nobody on our team had prior experience, except for a short but traumatic brush with IBM's Rational Functional Tester (remember kids: friends don't let friends use IBM products). To get rid of that, we decided to go ahead and try Selenium.
We initially recorded tests with the Firefox plugin but quickly realized that this wasn't maintainable and didn't really offer us good control for selecting elements. Our Tester Benjamin then took it upon him to write tests in Java and started to integrate them into our CI environment. Over time he created a solid set of Page Objects that allowed us to write new tests fairly quickly.
It took the rest of the team quite a while to take some ownership of these tests but eventually we came to a point where we'd sometimes even drive new features from these Selenium Tests.
There were hurdles along the way. Tests were brittle and the execution time was unacceptable (>30 mins). This improved with newer versions of Selenium, use of Selenium Grid to parallelize tests and by keeping a close eye on the VMs running the browser instances. In the case of IE(<8 gave="gave" just="just" p="p" simply="simply" up.="up." we="we">
Due to some relatively complex processes it was also fairly hard to test later stages of these processes. We only slowly got better at setting up test data for this without making use of the browser. This left us with some unfortunate holes in automated coverage.
There were still manual tests for each release for all of our major supported browsers. But with more of the core functionality being handled by automated tests and with the amount of changes shrinking due to shorter release cycles the effort for this went down considerably.
We also became better at writing unit and integration tests and our confidence in these grew.
What did I take away from it:
8>
- the demand for these tests was driven by Benjamin wanting to automate his tests to make his life easier. And also his desire to learn more about Java. It was a relatively clear goal and the benefits of effort spent on automation were fairly clear. Where automation was hard, it allowed him to balance that effort with the effort of doing the tests manually
- setting up and maintaining browser instances for tests and keeping them stable is hard, unthankful work and I'm glad that these days you can just hand money over to saucelabs to do that for you
- getting the CI builds to be reliably green made shared ownership easier. Collaboration on these tests continued to grow.
- closely related to that, the tests have to run fast. If they run for more than ten minutes they might as well not exist
- we had relatively few Selenium tests compared to our unit-tests but there were the odd cases of bugs that weren't caught by our normal test-suites
- when we rewrote a lot of the front-end JavaScript and test-drove those with jasmine, browser compatibility issues became very rare
- as our understanding of all the different tests grew, it became easier to decide when we could avoid writing an extra Selenium test
- working closely with the rest of the team and writing the tests in Java gave our Tester room to grow and learn and turn into a regular dev on the team. Seeing that happen was probably one of the most fun things during my time there. The rest of the team also took up some of the manual testing work.
(Edit 13.9.15: removed some point about testers that I didn't like anymore)
Continue on to part 2
Wednesday, April 4, 2012
Timetravelling in JavaScript unit tests
Labels:
javascript,
tdd,
testing
At the February berlinjs meet-up Krzysztof Szafranek had a very nice, short talk about TDD in JavaScript (slides here). Among many other things he was showing busterjs and the way it lets you test asynchronous stuff without having to actually wait for time to pass.
I made a note of it to give it a closer look. When I recently had to write some JavaScript again, I remembered about it and was keen to give it a try. Since we were already using jasmine as our testing framework, my colleague Christoph and I were looking for something equivalent there. To cut the intro short, there is: jasmine.Clock.
Sunday, January 9, 2011
Remember back then?
...back in 2010? That was a nice year. I have to say I'm pretty happy with how it turned out. There were some setbacks, first and foremost the departure of two colleagues whose knowledge and support I valued very highly, who left for new cities and new challenges. But such is life. But I learned a lot this year and got to make a lot of interesting experiences and meet a lot of interesting people.
It was a long year and this will be a long post. It will be self-indulgent and most likely only for my own benefit. So there.
First off, I finally took the time to finish reading Domain Driven Design, or "the great blue book in the sky" as I heard someone (probably Neil Robbins) call it. It was very timely as we were just in the process of redoing a fairly large part of our application. It gave me the confidence to split up the refactoring along the life cycle of our main entity, transforming it along the way. That way we were able to concentrate on the first step in the life cycle without having to change everything down the line, too.
Said refactoring was also the first time I remember of deliberately doing "refactoring toward deeper insight". The experience of taking what we had learned about the domain in the previous year and applying that to our domain model was surprisingly rewarding. The end result was a lot simpler and closer to how people actually worked. It gave us the opportunity to introduce new functionality that would otherwise have been extremely cumbersome to implement.
The whole process was not without its flaws though. We underestimated the amount of code we had to change, even with the reduced scope. Especially the front-end proved that good UI design is very hard and time-consuming. In hindsight we probably should have spent more time on considering how the changes might have been divided further into smaller, releasable pieces. In the end we were left with a long time between deployments and suffered all the communication issues that missing regular feedback loops can give you. It was still a good learning experience and it showed me how much I appreciated our previous, shorter deployment iterations.
In march I went to QCon, which I wrote about before. The inspiration I got turned out to have a fairly lasting effect. To get back to the kind of enthusiasm I had when I started out and to be able to really consciously enjoy coding again is something I am extremely grateful for. This wasn't necessarily all due to QCon but it encouraged me to be more introspective about how I work. In particular it had me putting more effort into getting better at TDD. At some point the whole "using tests to drive out the design" bit finally clicked and it made me a happier person.
There is still a lot left to improve though. Most of our bug-fixing work is now purely front-end stuff, ironing out layouting issues and Javascript behaviour across different browsers. But we're getting there. Writing jasmine tests is something I'll hopefully get better at and which integrates well enough into our builds. My colleague Benjamin put an amazing amount of work into getting a useful Selenium tool-set and tests for us. The environment for these is sadly still somewhat brittle but hopefully that will get better with Selenium 2.
We've made a lot of progress in automation anyway. Our test-environment gets automatically redeployed by Teamcity now. These are still very tiny baby-steps towards continuous delivery that conveniently ignore some of the larger issues like schema evolution and the need to switch to a DVCS but at least I think it's stumbling in the right direction.
I was also happy I got to help in making collaboration with our designers on different teams a little easier. Working on a bunch of projects in parallel while trying to consolidate on a consistent look & feel is something that has taken even more effort than I expected. And since look & feel is usually the most immediately apparent contact point for stakeholders, it is always under scrutiny. I underestimated that, too, even though I really should know better. All the more reason to push for further front-end test automation.
Later in the year our team worked on a new project and decided to base it on JSF 2, mostly so we could get the know-how. The other teams were already using it and it seemed reasonable to look for common ground there. I did learn a lot, but I didn't get much done. Having no one on the team with any prior experience meant we had to go through all the little beginners mistakes you get when you stumble into some new technology. Some of those early issues just rubbed me the wrong way which made me get increasingly frustrated. And I'm afraid my growing resentment probably didn't help the mood of the team.
This did bring up a few interesting questions about the effectiveness of aiming for a heterogeneous development environment. Questions which I don't really have answers for but still could ramble on about for hours. So I should probably put that in another post some day.
In November I was lucky enough to take part in a Code Retreat. Having been intrigued by that ever since I saw Corey Haines talk about it at QCon, I jumped at the chance to try it out. This, too, is worthy of its own post and so I won't go into details here. Suffice it to say that I liked it a lot and plan to organize a code retreat in Düsseldorf, to show it to more people.
(As an aside, I just stumbled over a google result for a code retreat in Wroclaw which brought a smile to my face. I always enjoyed my time there, when I visited there for another company, back in another time. And I always had a very high opinion of the people and their programming skills there. So, I guess this fits quite well.)
After Code Retreat Ghent came Google Developer Day Munich. It was nice to meet my now ex-colleague Sebastian again. And same as in Ghent, I was glad for the opportunity to chit-chat with other people in our profession. It never hurts putting things in perspective and hearing what others are passionate about. And of course, rambling about things I'm passionate about. (Something I find myself doing more of these days, I think. But maybe it was just the free beer provided by Google.)
The effort Google puts into these events was impressive and I really liked how non-partisan the speakers were. They openly acknowledged the existence of competitors (foremost Apple) without looking to discredit or awkwardly ignore their work.
I wasn't looking for anything in particular since my work currently targets neither HTML 5-capable browsers nor mobile phones, but at the end of the day I felt more sad about that fact. I wasn't aware how exciting some of the HTML 5 stuff is and I'm really looking forward to that becoming the norm and what people will be able to do with it.
Well, that about does it for two-oh-one-oh. Remaining, then, is the goals I've set myself for 2011 (I'm not yet convinced of spelling it 20!!).
Hmm... last and possibly least I just realized that I also started writing on this blog (and on twitter) this year. I guess I'll keep that up.
It was a long year and this will be a long post. It will be self-indulgent and most likely only for my own benefit. So there.
First off, I finally took the time to finish reading Domain Driven Design, or "the great blue book in the sky" as I heard someone (probably Neil Robbins) call it. It was very timely as we were just in the process of redoing a fairly large part of our application. It gave me the confidence to split up the refactoring along the life cycle of our main entity, transforming it along the way. That way we were able to concentrate on the first step in the life cycle without having to change everything down the line, too.
Said refactoring was also the first time I remember of deliberately doing "refactoring toward deeper insight". The experience of taking what we had learned about the domain in the previous year and applying that to our domain model was surprisingly rewarding. The end result was a lot simpler and closer to how people actually worked. It gave us the opportunity to introduce new functionality that would otherwise have been extremely cumbersome to implement.
The whole process was not without its flaws though. We underestimated the amount of code we had to change, even with the reduced scope. Especially the front-end proved that good UI design is very hard and time-consuming. In hindsight we probably should have spent more time on considering how the changes might have been divided further into smaller, releasable pieces. In the end we were left with a long time between deployments and suffered all the communication issues that missing regular feedback loops can give you. It was still a good learning experience and it showed me how much I appreciated our previous, shorter deployment iterations.
In march I went to QCon, which I wrote about before. The inspiration I got turned out to have a fairly lasting effect. To get back to the kind of enthusiasm I had when I started out and to be able to really consciously enjoy coding again is something I am extremely grateful for. This wasn't necessarily all due to QCon but it encouraged me to be more introspective about how I work. In particular it had me putting more effort into getting better at TDD. At some point the whole "using tests to drive out the design" bit finally clicked and it made me a happier person.
There is still a lot left to improve though. Most of our bug-fixing work is now purely front-end stuff, ironing out layouting issues and Javascript behaviour across different browsers. But we're getting there. Writing jasmine tests is something I'll hopefully get better at and which integrates well enough into our builds. My colleague Benjamin put an amazing amount of work into getting a useful Selenium tool-set and tests for us. The environment for these is sadly still somewhat brittle but hopefully that will get better with Selenium 2.
We've made a lot of progress in automation anyway. Our test-environment gets automatically redeployed by Teamcity now. These are still very tiny baby-steps towards continuous delivery that conveniently ignore some of the larger issues like schema evolution and the need to switch to a DVCS but at least I think it's stumbling in the right direction.
I was also happy I got to help in making collaboration with our designers on different teams a little easier. Working on a bunch of projects in parallel while trying to consolidate on a consistent look & feel is something that has taken even more effort than I expected. And since look & feel is usually the most immediately apparent contact point for stakeholders, it is always under scrutiny. I underestimated that, too, even though I really should know better. All the more reason to push for further front-end test automation.
Later in the year our team worked on a new project and decided to base it on JSF 2, mostly so we could get the know-how. The other teams were already using it and it seemed reasonable to look for common ground there. I did learn a lot, but I didn't get much done. Having no one on the team with any prior experience meant we had to go through all the little beginners mistakes you get when you stumble into some new technology. Some of those early issues just rubbed me the wrong way which made me get increasingly frustrated. And I'm afraid my growing resentment probably didn't help the mood of the team.
This did bring up a few interesting questions about the effectiveness of aiming for a heterogeneous development environment. Questions which I don't really have answers for but still could ramble on about for hours. So I should probably put that in another post some day.
In November I was lucky enough to take part in a Code Retreat. Having been intrigued by that ever since I saw Corey Haines talk about it at QCon, I jumped at the chance to try it out. This, too, is worthy of its own post and so I won't go into details here. Suffice it to say that I liked it a lot and plan to organize a code retreat in Düsseldorf, to show it to more people.
(As an aside, I just stumbled over a google result for a code retreat in Wroclaw which brought a smile to my face. I always enjoyed my time there, when I visited there for another company, back in another time. And I always had a very high opinion of the people and their programming skills there. So, I guess this fits quite well.)
After Code Retreat Ghent came Google Developer Day Munich. It was nice to meet my now ex-colleague Sebastian again. And same as in Ghent, I was glad for the opportunity to chit-chat with other people in our profession. It never hurts putting things in perspective and hearing what others are passionate about. And of course, rambling about things I'm passionate about. (Something I find myself doing more of these days, I think. But maybe it was just the free beer provided by Google.)
The effort Google puts into these events was impressive and I really liked how non-partisan the speakers were. They openly acknowledged the existence of competitors (foremost Apple) without looking to discredit or awkwardly ignore their work.
I wasn't looking for anything in particular since my work currently targets neither HTML 5-capable browsers nor mobile phones, but at the end of the day I felt more sad about that fact. I wasn't aware how exciting some of the HTML 5 stuff is and I'm really looking forward to that becoming the norm and what people will be able to do with it.
Well, that about does it for two-oh-one-oh. Remaining, then, is the goals I've set myself for 2011 (I'm not yet convinced of spelling it 20!!).
- Organize a code retreat, possibly making it a recurring event
- Look for more of these opportunities to learn from others
- Subversion is a nightmare to merge stuff with and I'm eager to switch to git but it would mean having to get used to a different workflow for everyone in the team. Maybe I'll start with a git kata.
- Follow through on all the "I should really write a blog post about that"
- Write more posts in german.
- Read GOOS, finish reading REST in Practice, glance over Continuous Delivery.
- Try to solve more problems event-driven
Hmm... last and possibly least I just realized that I also started writing on this blog (and on twitter) this year. I guess I'll keep that up.
Friday, November 26, 2010
Javascript TDD with jasmine and maven
Labels:
javascript,
maven,
tdd
Edit[04/2011]: Since I seem to get the odd google hit on this it is worth pointing out that Justin Searls has since updated the plugin to include a lot more useful configuration options and also made it available in the maven central repo. So you can just use it straight away by following the instructions.
Edit[05/2011]: and now there is also this awesome site where you can try out jasmine and even do it in coffee script - all in your browser. Happy pandas all around!
As the amount of javascript in our project has grown quite considerably, it was time to get rid of this black spot in our test coverage. And since I'm getting more and more used to test-drive the code I'm writing, it was especially annoying to have to regress to trial-and-erring for the javascript part of our code.
I was overwhelmed by the choice of testing frameworks but eventually settled on jasmine, as that seems to be the most widely supported one with a reasonable syntax.
As all testing that is not automated might as well not exist it was important that it was possible to integrate it into our Teamcity setup. Thankfully, seraching for jasmine and maven quickly pointed me to jasmine-maven-plugin.
This plugin builds a html test runner that includes all javascript files in your project and then gets accessed with htmlunit and can run during the maven test phase, requiring no changes to our Teamcity build configuration.
Since we have a bunch of library and legacy javascript code that takes offence to being included directly I needed a way to filter which files actually got included in the test. There was some slightly out-of-date fork on github that included changes to configure inclusion and exclusion patterns which I was able to adapt to the current version (Which is available here).
The nice thing here is that all files are still copied to the target directory and the exclusions only affect what files get loaded in the test runner which proved useful soon enough.
I wasn't really happy just expecting all files to be loaded in the tests since that is not likely how it would happen in the deployed code. I am hoping to have the test specs define what other files are required by a specific functionality. Since all files get copied it is easy enough just loading them from inside the tests. I'm not quite happy with that yet as globals don't get reset between different jasmine Specs but it should be easy enough to add that functionality at some point.
Another nice feature of the maven plugin is the inclusion of other javascript artifacts. This way you can deploy libraries like jquery to your local maven repository and have them automatically included in your test runner.
So, with that said, this is what I currently have in our maven configuration:
Most of the options are explained very well in the main jasmine-maven-plugin README. I've only changed the plugin version to our own locally deployed version and made use of the new include option. This will only include files named *_spec.js in the test runner. The specs will then load additional files themselves.
Edit[05/2011]: and now there is also this awesome site where you can try out jasmine and even do it in coffee script - all in your browser. Happy pandas all around!
As the amount of javascript in our project has grown quite considerably, it was time to get rid of this black spot in our test coverage. And since I'm getting more and more used to test-drive the code I'm writing, it was especially annoying to have to regress to trial-and-erring for the javascript part of our code.
I was overwhelmed by the choice of testing frameworks but eventually settled on jasmine, as that seems to be the most widely supported one with a reasonable syntax.
As all testing that is not automated might as well not exist it was important that it was possible to integrate it into our Teamcity setup. Thankfully, seraching for jasmine and maven quickly pointed me to jasmine-maven-plugin.
This plugin builds a html test runner that includes all javascript files in your project and then gets accessed with htmlunit and can run during the maven test phase, requiring no changes to our Teamcity build configuration.
Since we have a bunch of library and legacy javascript code that takes offence to being included directly I needed a way to filter which files actually got included in the test. There was some slightly out-of-date fork on github that included changes to configure inclusion and exclusion patterns which I was able to adapt to the current version (Which is available here).
The nice thing here is that all files are still copied to the target directory and the exclusions only affect what files get loaded in the test runner which proved useful soon enough.
I wasn't really happy just expecting all files to be loaded in the tests since that is not likely how it would happen in the deployed code. I am hoping to have the test specs define what other files are required by a specific functionality. Since all files get copied it is easy enough just loading them from inside the tests. I'm not quite happy with that yet as globals don't get reset between different jasmine Specs but it should be easy enough to add that functionality at some point.
Another nice feature of the maven plugin is the inclusion of other javascript artifacts. This way you can deploy libraries like jquery to your local maven repository and have them automatically included in your test runner.
So, with that said, this is what I currently have in our maven configuration:
Most of the options are explained very well in the main jasmine-maven-plugin README. I've only changed the plugin version to our own locally deployed version and made use of the new include option. This will only include files named *_spec.js in the test runner. The specs will then load additional files themselves.
Subscribe to:
Posts (Atom)