DZone Interview – Benefits of Testable Code
posted on November 18th, 2009 ·
→ 4 CommentsTags: Uncategorized
How to get Started with TDD
posted on November 17th, 2009 ·
Best way to learn TDD is to have someone show you while pairing with you. Short of that, I have set up an eclipse project for you where you can give it a try:
- hg clone https://bitbucket.org/misko/misko-hevery-blog/
- Open project blog/tdd/01_Calculator in Eclipse.
- It should be set up to run all tests every time you modify a file.
- You may have to change the path to java if you are not an Mac OS.
- Project -> Properties -> Builders -> Test -> Edit
- Change location to your java
- Right-click on Calculator.java -> Run As -> Java Application to run the calculator
Your mission is to make the calculator work using TDD. This is the simplest form of TDD where you don’t have to mock classes or create complex interactions, so it should be a good start for beginners.
TDD means:
- write a simple test, and assert something interesting in it
- implement just enough to make that tests green (nothing more, or you will get ahead of your tests)
- then write another test, rinse, and repeat.
I have already done all of the work of separating the behavior from the UI, so that the code is testable and properly Dependency Injected, so you don’t have to worry about running into testability issues.
- Calculator.java: This is the main method and it is where all of the wiring is happening.
- CalculatorView.java: This is a view and we don’t usually bother unit testing it has cyclomatic complexity of one, hence there is no logic. It either works or does not. Views are usually good candidates for end-to-end testing, which is not part of this exercise.
- CalculatorModel.java: is just a PoJo which marshals data from the Controller to the View, not much to test here.
- CalculatorController.java: is where all of your if statements will reside, and we need good tests for it.
I have started you off with first ‘testItShouldInitializeToZero’ test. Here are some ideas for next tests you may want to write.
- testItShouldConcatinateNumberPresses
- testItShouldSupportDecimalPoint
- testItShouldIgnoreSecondDecimalPoint
- testItShouldAddTwoIntegers
I would love to see what you will come up with and what your thoughts are, after you get the whole calculator working. I would also encourage you to post interesting corner case tests here for others to incorporate. If you want to share your code with others, I would be happy to post your solutions.
Good luck!
PS: I know it is trivial example, but you need to start someplace.
→ 26 CommentsTags: Uncategorized
GTAC 2009 – JsTestDriver
posted on November 6th, 2009 ·
Google Tech Talk
October 22, 2009
ABSTRACT
Presented by Jeremie Lenfant -Engelmann, Google, at the 4th Annual Google Test Automation Conference, October 21st, 22nd, 2009, Zurich, CH
The proliferation of JavaScript unit-testing frameworks in the JavaScript community shows that no one has yet found the magical combination of features to make JavaScript testing a no-brainer. We like to believe that JsTestDriver will change that by redefining JavaScript testing frameworks and as a result will deliver something which at first glance seems impossible. As a developer of JavaScript I want to write my production and test code in my favorite IDE. When I make a code change, I want a save action to trigger a rerun off all of my tests on all browsers and platforms and report the results under 1 second. All of this without ever leaving my favorite IDE. JsTestDriver achieves all of the above by capturing any number of browser slaves from multiple platforms. In order to run at high speed we do not render our results in the browser but report the errors on the command line. JsTestDriver also loads and parses JavaScript files eagerly, only reloading files that have changed. JsTestDriver can execute hundreds of tests per browser and execute them on all of the captured browsers in parallel. Thanks to these practices we achieve extremely high throughput. We want to be a test-runner platform and allow others to build assertion frameworks on top of JsTestDriver. This way the open-source community can focus on building a better way of testing and not worry about how to run the tests across all of the browsers, platforms and in a continuous build environment.
http://code.google.com/p/js-test-driver
Bio: Jeremie Lenfant-Engelmann works for Google and is the lead developer of JsTestDriver.
Video: http://www.youtube.com/watch?v=aDKGGZv-T4M
→ 2 CommentsTags: Uncategorized
How To Write Hard To Test Code & What To Look For When Reviewing Other Peoples Hard To Test Code
posted on October 28th, 2009 ·
Here are my slides which Cory Smith and I have presented this morning at OOPSLA 2009.
The ability to write hard to test code is innate in every developer form the moment we have built our first “Hello World” application. It is so automatic that we do not even know when we are doing it. On the other hand writing testable code requires that you un-learn this behavior. In this tutorial you will learn how to recognize the red flags in the code and what are the common solutions for them. We will look at sample code representing common development practices and look into subtleties why this code is hard to test and how to fix it. The goal of the tutorial is to arm you with knowledge of how to write code which can be tested using small focused tests.
Slides: view slides in PDF format here
→ 6 CommentsTags: Uncategorized
Automatic Dependency Injection In The Land Of Dynamic Languages
posted on October 25th, 2009 ·
Automatic Dependency Injection Frameworks (such as GUICE, PicoContainer, and Spring) are very popular in Java, where they depend heavily on static typing, interfaces, reflection and annotations. But what about languages such as ActionScript, JavaScript, Python and Ruby, where duck-typing and lack of run-time-type-information at first glance make these frameworks impossible? Can a simple Dependency Injection Framework framework be built? We’ll look at how the power of functional programing and functions as first class citizens in these languages can be leveraged to build a simple and effective dependency injection framework. We’ll also explore the power of using such a framework in dynamic languages. To illustrate these ideas we will convert a JavaScript application which uses manual Dependency Injection into one using Automatic Dependency Injection Framework.
The framework implementation can be found here: http://bitbucket.org/misko/misko-hevery-oopsla-09/overview/
The paper can be found here: http://misko.hevery.com/wp-content/uploads/2009/10/tut0000021-hevery.pdf
To get the injection code make sure to switch branches to “inject”
→ 5 CommentsTags: Uncategorized
Lowering the price of Web-Apps
posted on October 18th, 2009 ·
The old saying goes: Ideas are a dime a dozen, it’s the execution that counts.
So you are working on a project and all of a sudden you realize that it would be great to have a web-application which keeps track of something. It is exactly what would hit the spot, but than you think about it some more and you realize that your choices are
- Custom app in php/java/ruby/rails/etc… would take you days to get up and running and than there is the cost of deployment. You have full control of everything but you have to be an expert in everything.
- You could use Google docs (spreadsheet) but that does not have the right look and feel, as you can either have form for collecting data or you can have tabular data. You have zero control of the presentation.
So you think about it some more and you realize that the benefits are not worth the effort and the application does not get build. How often has this happen to you?
<angular/> is not about making the building of web-applications easier, it is about allowing you to build an application where no application would have been build before.
Let me give you an example. I do a lot of coding and often I get distracted. So I said, I would love to know the reasons why I get distracted. Would it not be great if I could keep a log, which would than draw a chart for me with how often and why I get distracted? I could have opened a spreadsheet, but somehow the act of opening a spreadsheet is a distraction in itself, so I doubt I would have done it every time I got distracted. So instead I took 5 minutes to hack together a quick HTML which allowed me to enter the reason why I was distracted in <angular/>. Now I am a mac user, so I click the “Open in Dashboard” on my safari and I had a dashboard widget which allows me to keep track of the reasons whenever I get distracted, with very little effort. I stop coding because I need to go to meeting, I activate Dashboard and enter the reason, someone comes over and asks me a question, ditto.
<angular/> allowed me to go from an idea to working app in 5 minutes. If it was not for <angular/> this simple app would simply not get built. It is great when technology makes existing things easier, it is even better when it enables things which simply would not have happened.
Wait! I have an idea, it would be great to get your opinion on what kind of quick and dirty applications you always wanted to build but the effort was not worth the benefit. What if, we could also vote on other peoples ideas too.
Well here it is:
Your Idea:
- Votes: like it:{{idea.yes}}; hate it:{{idea.no}} | {{idea.$audit.created.by}} | {{idea.description}}
→ 5 CommentsTags: Uncategorized
Design for Testability Talk
posted on October 7th, 2009 ·
Here is may latest presentation on design for testability…
Slides: Design For Testablity
→ 12 CommentsTags: Uncategorized
Sweet Spot for <angular/>
posted on October 4th, 2009 ·
Building web-applications is hard! Even the simplest hello world application will take you hours to set up and you have to know a lot about how many different pieces of technologies work together. Here is a quick inventory from the browser to the back end of what a typical web-application developer needs to know about: HTML, CSS, JavaScript, cookies, HTTP, URL encodings, Servlets, web-framework (i.e. web-work), authentication, threading, SQL, ObjectRelational mappers, DB Schema, RDMS, DB indexing. If you know all of that, than you have a good chance that after week of work, you can have a hello world application written which will allow the user to authenticate, and persist some data.
But, if you think about it most web-applications are just pretty UI on top of database CRUD (create, read, update, delete). Everything else you do is a constant marshaling of data back and forth. From the HTML input, to URL parameters, to HttpRequest, to BussinessObject, to Value Object, to SQL. Hope you did not make any mistakes, as now you have to do all of this in reverse.
The goal of <angular/> is to make CRUD applications easy to build. <angular/> is not a generic framework where you can build any kind of application, its sweet spot are CRUD web-applications.
We believe that there are many web-application which do not get build because the cost of building them is prohibitive. With <angular/> the cost of building these simple applications is greatly reduced.
While building <angular/> we had few goals in mind:
Managed Database
Building a web-applications is just half the battle, deploying them is another. Now you need to rent a host in the data-center where you can deploy the application, where the database can run. I hope you know how to administer and back up your database. <angular/> provides the database hosting as a service so that your <angular/> application does not have to worry about it.
HTML & CSS
There are a lot more web-designers out there than web-developers. We wanted to make <angular/> simple enough where many of the web-designers, which do not know how to program can now move to the business of building simple web-applications and hence provide a greater value to their customers. In order to build a simple web-application a knowledge of HTML & CSS is all which you need to know. The best way to think about <angular/> is that it is HTML with few extra attributes.
Security/Authentication
The cost of building security and authentication into your web-application is often overlooked when building web-applications. <angular/> offers both out of the box.
Embeddable
There are many ways to get your HTML published. (Blogs, Wikis, Content Management systems, to name a few) <angular/> allows you to enhance all of these pages behavior by adding the power of CRUD to these pages. Embeddability opens up a whole new set of possibilities of enhancing existing web-pages or creating mash ups.
Declarative
I can teach HTML to almost anyone (willing to learn) in just a few minutes. Teaching programming languages such as JavaScript requires weeks of work, and that is if you already know how to program. The difference is that HTML is declarative whereas JavaScript is procedural. You describe how the page looks like, vs instructing the browser how to draw one. This is a huge for the learning curve. Declarative vs procedural is the difference between web-designer and the web-developer.
Rich Widgets
Finally, HTML forms have very limited widgets, you want date-picker? charts? maps? form validation? barcodes? formatters? well you have to go and integrate some JavaScript library and you have to know how to program (vs declaring what you want). We want to extend the HTML so that you can ask for these widgets in declarative fashion in <angular/>.
→ 3 CommentsTags: Uncategorized
Cost of Testing
posted on October 1st, 2009 ·
A lot of people have been asking me lately, what is the cost of testing, so I decided, that I will try to measure it, to dispel the myth that testing takes twice as long.
For the last two weeks I have been keeping track of the amount of time I spent writing tests versus the time writing production code. The number surprised even me, but after I thought about it, it makes a lot of sense. The magic number is about 10% of time spent on writing tests. Now before, you think I am nuts, let me back it up with some real numbers from a personal project I have been working on.
Total | Production | Test | Ratio | |
---|---|---|---|---|
Commits | 1,347 | 1,347 | 1,347 | |
LOC | 14,709 | 8,711 | 5,988 | 40.78% |
JavaScript LOC | 10,077 | 6,819 | 3,258 | 32.33% |
Ruby LOC | 4,632 | 1,892 | 2,740 | 59.15% |
Lines/Commit | 10.92 | 6.47 | 4.45 | 40.78% |
Hours(estimate) | 1,200 | 1,080 | 120 | 10.00% |
Hours/Commit | 0.89 | 0.80 | 0.09 | |
Mins/Commit | 53 | 48 | 5 |
Commits refers to the number of commits I have made to the repository. LOC is lines of code which is broken down by language. The ratio shows the typical breakdown between the production and test code when you test drive and it is about half, give or take a language. It is interesting to note that on average I commit about 11 lines out of which 6.5 are production and 4.5 are test. Now, keep in mind this is average, a lot of commits are large where you add a lot of code, but then there are a lot of commits where you are tweaking stuff, so the average is quite low.
The number of hours spent on the project is my best estimate, as I have not kept track of these numbers. Also, the 10% breakdown comes from keeping track of my coding habits for the last two weeks of coding. But, these are my best guesses.
Now when I test drive, I start with writing a test which usually takes me few minutes (about 5 minutes) to write. The test represents my scenario. I then start implementing the code to make the scenario pass, and the implementation usually takes me a lot longer (about 50 minutes). The ratio is highly asymmetrical! Why does it take me so much less time to write the scenario than it does to write the implementation given that they are about the same length? Well look at a typical test and implementation:
Here is a typical test for a feature:
ArrayTest.prototype.testFilter = function() { var items = ["MIsKO", {name:"john"}, ["mary"], 1234]; assertEquals(4, items.filter("").length); assertEquals(4, items.filter(undefined).length); assertEquals(1, items.filter('iSk').length); assertEquals("MIsKO", items.filter('isk')[0]); assertEquals(1, items.filter('ohn').length); assertEquals(items[1], items.filter('ohn')[0]); assertEquals(1, items.filter('ar').length); assertEquals(items[2], items.filter('ar')[0]); assertEquals(1, items.filter('34').length); assertEquals(1234, items.filter('34')[0]); assertEquals(0, items.filter("I don't exist").length); }; ArrayTest.prototype.testShouldNotFilterOnSystemData = function() { assertEquals("", "".charAt(0)); // assumption var items = [{$name:"misko"}]; assertEquals(0, items.filter("misko").length); }; ArrayTest.prototype.testFilterOnSpecificProperty = function() { var items = [{ignore:"a", name:"a"}, {ignore:"a", name:"abc"}]; assertEquals(2, items.filter({}).length); assertEquals(2, items.filter({name:'a'}).length); assertEquals(1, items.filter({name:'b'}).length); assertEquals("abc", items.filter({name:'b'})[0].name); }; ArrayTest.prototype.testFilterOnFunction = function() { var items = [{name:"a"}, {name:"abc", done:true}]; assertEquals(1, items.filter(function(i){return i.done;}).length); }; ArrayTest.prototype.testFilterIsAndFunction = function() { var items = [{first:"misko", last:"hevery"}, {first:"mike", last:"smith"}]; assertEquals(2, items.filter({first:'', last:''}).length); assertEquals(1, items.filter({first:'', last:'hevery'}).length); assertEquals(0, items.filter({first:'mike', last:'hevery'}).length); assertEquals(1, items.filter({first:'misko', last:'hevery'}).length); assertEquals(items[0], items.filter({first:'misko', last:'hevery'})[0]); }; ArrayTest.prototype.testFilterNot = function() { var items = ["misko", "mike"]; assertEquals(1, items.filter('!isk').length); assertEquals(items[1], items.filter('!isk')[0]); };
Now here is code which implements this scenario tests above:
Array.prototype.filter = function(expression) { var predicates = []; predicates.check = function(value) { for (var j = 0; j < predicates.length; j++) { if(!predicates[j](value)) { return false; } } return true; }; var getter = Scope.getter; var search = function(obj, text){ if (text.charAt(0) === '!') { return !search(obj, text.substr(1)); } switch (typeof obj) { case "bolean": case "number": case "string": return ('' + obj).toLowerCase().indexOf(text) > -1; case "object": for ( var objKey in obj) { if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) { return true; } } return false; case "array": for ( var i = 0; i < obj.length; i++) { if (search(obj[i], text)) { return true; } } return false; default: return false; } }; switch (typeof expression) { case "bolean": case "number": case "string": expression = {$:expression}; case "object": for (var key in expression) { if (key == '$') { (function(){ var text = (''+expression[key]).toLowerCase(); if (!text) return; predicates.push(function(value) { return search(value, text); }); })(); } else { (function(){ var path = key; var text = (''+expression[key]).toLowerCase(); if (!text) return; predicates.push(function(value) { return search(getter(value, path), text); }); })(); } } break; case "function": predicates.push(expression); break; default: return this; } var filtered = []; for ( var j = 0; j < this.length; j++) { var value = this[j]; if (predicates.check(value)) { filtered.push(value); } } return filtered; };
Now, I think that if you look at these two chunks of code, it is easy to see that even though they are about the same length, one is much harder t write. The reason, why tests take so little time to write is that they are linear in nature. No loops, ifs or interdependencies with other tests. Production code is a different story, I have to create complex ifs, loops and have to make sure that the implementation works not just for one test, but all test. This is why it takes you so much longer to write production than test code. In this particular case, I remember rewriting this function three times, before I got it to work as expected.
So a naive answer is that writing test carries a 10% tax. But, we pay taxes in order to get something in return. Here is what I get for 10% which pays me back:
- When I implement a feature I don’t have to start up the whole application and click several pages until I get to page to verify that a feature works. In this case it means that I don’t have to refreshing the browser, waiting for it to load a dataset and then typing some test data and manually asserting that I got what I expected. This is immediate payback in time saved!
- Regression is almost nil. Whenever you are adding new feature you are running the risk of breaking something other then what you are working on immediately (since you are not working on it you are not actively testing it). At least once a day I have a what the @#$% moment when a change suddenly breaks a test at the opposite end of the codebase which I did not expect, and I count my lucky stars. This is worth a lot of time spent when you discover that a feature you thought was working no longer is, and by this time you have forgotten how the feature is implemented.
- Cognitive load is greatly reduced since I don’t have to keep all of the assumptions about the software in my head, this makes it really easy to switch tasks or to come back to a task after a meeting, good night sleep or a weekend.
- I can refactor the code at will, keeping it from becoming stagnant, and hard to understand. This is a huge problem on large projects, where the code works, but it is really ugly and everyone is afraid to touch it. This is worth money tomorrow to keep you going.
These benefits translate to real value today as well as tomorrow. I write tests, because the additional benefits I get more than offset the additional cost of 10%. Even if I don’t include the long term benefits, the value I get from test today are well worth it. I am faster in developing code with test. How much, well that depends on the complexity of the code. The more complex the thing you are trying to build is (more ifs/loops/dependencies) the greater the benefit of tests are.
So now you understand my puzzled look when people ask me how much slower/costlier the development with tests is.
→ 31 CommentsTags: Uncategorized
Hello World, <angular/> is here
posted on September 28th, 2009 ·
If you see this text, than you are not reading this blog on our site, and the page will be static. To get the full effect please read the original blog on http://blog.getangular.com/2009/09/26/hello-world-angular-is-here/
Hi I am <angular/>! What is your name? (Please enter your name into the text box).
Hello {{person.name}}! Please to meet you!
We would like to introduce to you a new way of building web applications! All you need is basic working of HTML & CSS and you can declaratively build a web-application in minutes.
Here are the kinds of things yo can do:
- Bring static HTML to life with just a few keystrokes.
- Persist your data in the cloud
- Embed your application in existing web page, such as this blog article
Here is what you need to know:
- Basic Knowledge of HTML & CSS
- Optional: JavaScript if you want to take the application to the next level.
Here is what you DO NOT NEED to know:
- Databases or SQL.
- Back end technology such as Java, Ruby, C# or the likes.
- For most things, you don’t even need to be a programer.
Well {{person.name}}, believe it or not, but this page is just a wordpress blog written in few minutes with a text editor. I have than added few extra angular tags to the HTML and the page came alive as you can see. Let me take you on the tour of what <angular/> can do.
Why don’t you tell me what you like to do for fun:
Hobby:
{{person.name}} likes to:
- {{hobby}} [ X ]
Now lets save your hobbies:
Great! here is a QR code which if you scan with your iPhone (App: NeoReader) or Android Phone (App: Barcode reader) it will take you back to this page:
{{$window.location.href|qrcode}}
Congrats {{person.name}}, you have successfully saved your hobbies to the cloud. To access them later here is a permanent url which you can send to your friends or use to edit your hobbies later: {{$window.location.href}}
I am sure you are wondering how all of this magic is made. Well, here is a hint, go watch the screen-cast here. Than come back and check the source of this page, as well as the debug view of the internal state of the page here:
person={{person}}
<angular/> is still in beta, but we are looking for few brave souls to start building web apps and give us feedback. As a beta user we will work closely with you to help you get started and resolve any issues which you may run into. If interested, sign up on our mailing list (http://groups.google.com/group/angular) and send us an email with the kind of application you would like to build.
Happy coding and looking forward to hear from you…
The <angular/> team.