Xem mẫu

Automated Testing As web developers it is easy to find ourselves in situations where we spend un-healthyamountsoftimewiththerefreshbuttoninourbrowsers.Youknowthedrill: type some code in your text editor, Alt+Tab to the browser, hit F5. Lather, rinse, repeat. This sort of manual testing is time-consuming, error-prone, and irrepro-ducible. Given that our web applications are expected to run on a vast combination of browsers and platforms, testing them all manually will inevitably become an impossible task. So we focus on a few combinations and perform the occasional check-up on the broader selection. The end result is an unsatisfactory development process and possibly brittle solutions. Overtheyearslotsoftoolshaveemergedtoimproveourlivesaswebdevelopers. Wenowhavedevelopertoolsforallthemajorbrowsers,thereareseveralJavaScript debuggers to choose from, and even IDEs to spot typos and other mistakes. Spend-ing some time in Firefox’s Firebug plugin interacting with an application sure beats those pesky alerts, but we’re still stuck with a manual, error-prone, and time-consuming debugging process. Humans are lazy, programmers even more so. When manual processes slow us down,weseektoautomatethemanualbehavior,allowingustospendourtimedoing something meaningful. In fact, as web developers, our job is more often than not to automate some tedious task in order to improve business value. Online banking is a great example—instead of going to the bank, standing in line and interacting Download from www.eBookTM.com 3 4 Automated Testing with another human to move some cash from account A to account B, we simply log in from the comfort of our couch and get the job done in a couple of minutes. Saves us time and saves the bank time. Automated testing provides a solution to the manual testing process. Instead of filling out that form one more time and hitting submit to see if the client-side validations trigger as expected, we can instruct software to perform this test for us. The advantages are obvious: given a convenient way to run the automated test we can test in numerous browsers with a single effort, we can rerun the test at any later stage, and the test may even run on some schedule that requires no manual interaction whatsoever. Automated software testing has been around for quite a while, even for JavaScript. JsUnit dates back to 2001, Selenium came along in 2004, and since then an incredible amount of tools have emerged. Still, automated testing seems to have less momentum in the JavaScript/web development community than most other programming communities. In this chapter we’ll investigate one means to automate software testing, the unit test, and how it applies to the world of JavaScript. 1.1 The Unit Test A unit test is a piece of code that tests a piece of production code. It does so by setting up one or a few more objects in a known state, exercising them (e.g., calling a method), and then inspecting the result, comparing it to the expected outcome. Unit tests are stored on disk and should be easy and fast to run; if tests are hard or slow to run, developers are less likely to run them. Unit tests should test software components in isolation. They should also run isolated—no test should ever depend on another test, tests should be able to run simultaneously and in any order. In order to test components in isolation, it is sometimes necessary to mock or stub their dependencies. We will discuss mocking and stubbing in context in Part III, Real-World Test-Driven Development in JavaScript and in more detail in Chapter 16, Mocking and Stubbing. Having unit tests stored on disk, and usually stored in version control along with the production code, means we can run tests at any time: • When the implementation is complete, to verify its correct behavior • When the implementation changes, to verify its behavior is intact • When new units are added to the system, to verify it still fulfills its intended purpose Download from www.eBookTM.com 1.1 The Unit Test 5 1.1.1 Unit Testing Frameworks Unit tests are usually written using a unit testing framework, although that is not strictly necessary. In this chapter we’ll focus on the concept of unit tests, working throughthedifferentaspectsofwritingandrunningthem.We’lldeferthediscussion of actual testing frameworks for JavaScript to Chapter 3, Tools of the Trade. It’s likely that you’ve already written more than a few unit tests, even if you have never done any structured unit testing. Whenever you pop up a console in a browser (e.g., Firebug, Safari’s Inspector or others) to debug or play live with your code, you probably issue some statements and inspect the resulting state of the involved objects. In many cases this is unit testing, only it isn’t automated and it’s not reproducible. We’ll work through an example of this kind of testing and gradually formalize it as an xUnit test case. xUnit is a common way to refer to test frameworks that are either a direct port of JUnit, or more loosely based on the ideas and concepts in it—or, more correctly, the ideas and concepts in SUnit, the Smalltalk testing framework. Kent Beck, the fatherofextremeprogramming,playedanintegralpartinthecreationofboththese frameworks, and even though SUnit was the first implementation, JUnit has done the most in terms of popularizing the pattern. 1.1.2 strftimefor JavaScript Dates Manyprogramminglanguagesprovideastrftimefunctionorsimilar.Itoperates on a date or timestamp, accepts a format string, and produces a formatted string that represents the date. For example, in Ruby, strftimeis available as a method on time and date objects, and Listing 1.1 shows an example of its use. Listing 1.1 Time#strftime in Ruby Time.now.strftime("Printed on %m/%d/%Y") #=> "Printed on 09/09/2010" Listing 1.2 shows an early attempt at implementing strftimefor JavaScript. It’s implemented on Date.prototypewhich makes it available as a method on all date objects. Don’t despair should you find it hard to understand all the details of the code in this chapter. Concepts are more important than the actual code, and most advanced techniques will be discussed in Part II, JavaScript for Programmers. Listing 1.2 Starting point for strftime for JavaScript Date.prototype.strftime = (function () { function strftime(format) { Download from www.eBookTM.com 6 Automated Testing var date = this; return (format + "").replace(/%([a-zA-Z])/g, function (m, f) { var formatter = Date.formats && Date.formats[f]; if (typeof formatter == "function") { return formatter.call(Date.formats, date); } else if (typeof formatter == "string") { return date.strftime(formatter); } return f; }); } // Internal helper function zeroPad(num) { return (+num < 10 ? "0" : "") + num; } Date.formats = { // Formatting methods d: function (date) { return zeroPad(date.getDate()); }, m: function (date) { return zeroPad(date.getMonth() + 1); }, y: function (date) { return date.getYear() % 100; }, Y: function (date) { return date.getFullYear(); }, // Format shorthands F: "%Y-%m-%d", D: "%m/%d/%y" }; return strftime; }()); Download from www.eBookTM.com 1.1 The Unit Test 7 Date.prototype.strftimemainly consists of two parts: the replace function which takes care of replacing format specifiers with their corresponding values, and the Date.formatsobject which is a collection of helpers. It can be broken down as follows: • Date.formatsis an object with format specifiers as keys and methods to extract the corresponding data from a date as values • Some format specifiers are convenient shortcuts to longer formats • String.prototype.replaceis used with a regexp that matches format specifiers • The replacer function checks if a given specifier is available on Date. formatsand uses it if it is, otherwise the specifier is left untouched (i.e., returned directly) How would we go about testing this method? One way is to include the script in our web page and use it where we need it and then verify manually if the website displays dates correctly. If it doesn’t work, we probably won’t get a lot of hints as to why, and are left debugging. A slightly more sophisticated approach (although not by much) is to load it in a web page and pop open a console and play around with it. Perhaps something like the session in Listing 1.3. Listing 1.3 Manually checking code in Firebug >>> var date = new Date(2009, 11, 5); >>> date.strftime("%Y"); "2009" >>> date.strftime("%m"); "12" >>> date.strftime("%d"); "05" >>> date.strftime("%y"); "9" Uh-oh. Our Firebug session indicates all is not well with our strftime. This means we’ll have to investigate and rerun the test to verify that it’s working. That’s more manual labor. We can do better. Let’s create a minimal HTML page where we load in the source script along with another script where we add some test code. This way we can inspect the result of changes without having to retype the tests. Listing 1.4 shows the HTML page that we’ll use to test. Download from www.eBookTM.com ... - tailieumienphi.vn
nguon tai.lieu . vn