Ebook Test-Driven JavaScript Development – Christian Johanse

Test-Driven JavaScript Development
Test-Driven JavaScript Development

Download

THÔNG TIN TÀI LIỆU

Nhà xuất bản Pearson Education
Tác giả Christian Johansen
Số trang 525
Ngày xuất bản 2011
File PDF

NỘI DUNG TÀI LIỆU
Part I Test-Driven Development 1
1. Automated Testing 3
1.1 The Unit Test 4
1.1.1 Unit Testing Frameworks 5
1.1.2 strftime for JavaScript Dates 5
1.2 Assertions 9
1.2.1 Red and Green 10
1.3 Test Functions, Cases, and Suites 11
1.3.1 Setup and Teardown 13
1.4 Integration Tests 14
1.5 Benefits of Unit Tests 16
1.5.1 Regression Testing 16
1.5.2 Refactoring 17
1.5.3 Cross-Browser Testing 17
1.5.4 Other Benefits 17
1.6 Pitfalls of Unit Testing 18
1.7 Summary 18

2. The Test-Driven Development Process 21
2.1 Goal and Purpose of Test-Driven Development 21
2.1.1 Turning Development Upside-Down 22
2.1.2 Design in Test-Driven Development 22
2.2 The Process 23
2.2.1 Step 1: Write a Test 24
2.2.2 Step 2: Watch the Test Fail 25
2.2.3 Step 3: Make the Test Pass 26
2.2.3.1 You Ain’t Gonna Need It 26
2.2.3.2 Passing the Test for String.prototype.trim 27
2.2.3.3 The Simplest Solution that Could Possibly Work 27
2.2.4 Step 4: Refactor to Remove Duplication 28
2.2.5 Lather, Rinse, Repeat 29
2.3 Facilitating Test-Driven Development 29
2.4 Benefits of Test-Driven Development 30
2.4.1 Code that Works 30
2.4.2 Honoring the Single Responsibility Principle 30
2.4.3 Forcing Conscious Development 31
2.4.4 Productivity Boost 31
2.5 Summary 31

3. Tools of the Trade 33
3.1 xUnit Test Frameworks 33
3.1.1 Behavior-Driven Development 34
3.1.2 Continuous Integration 34
3.1.3 Asynchronous Tests 35
3.1.4 Features of xUnit Test Frameworks 35
3.1.4.1 The Test Runner 35
3.1.5 Assertions 36
3.1.6 Dependencies 37
3.2 In-Browser Test Frameworks 37
3.2.1 YUI Test 38
3.2.1.1 Setup 38
3.2.1.2 Running Tests 40
3.2.2 Other In-Browser Testing Frameworks 40
3.3 Headless Testing Frameworks 41
3.3.1 Crosscheck 42
3.3.2 Rhino and env.js 42
3.3.3 The Issue with Headless Test Runners 42
3.4 One Test Runner to Rule Them All 42
3.4.1 How JsTestDriver Works 43
3.4.2 JsTestDriver Disadvantages 44
3.4.3 Setup 44
3.4.3.1 Download the Jar File 44
3.4.3.2 Windows Users 45
3.4.3.3 Start the Server 45
3.4.3.4 Capturing Browsers 46
3.4.3.5 Running Tests 46
3.4.3.6 JsTestDriver and TDD 48
3.4.4 Using JsTestDriver From an IDE 49
3.4.4.1 Installing JsTestDriver in Eclipse 49
3.4.4.2 Running JsTestDriver in Eclipse 50
3.4.5 Improved Command Line Productivity 51
3.4.6 Assertions 51
3.5 Summary 52

4. Test to Learn 55
4.1 Exploring JavaScript with Unit Tests 55
4.1.1 Pitfalls of Programming by Observation 58
4.1.2 The Sweet Spot for Learning Tests 59
4.1.2.1 Capturing Wisdom Found in the Wild 59
4.1.2.2 Exploring Weird Behavior 59
4.1.2.3 Exploring New Browsers 59
4.1.2.4 Exploring Frameworks 60
4.2 Performance Tests 60
4.2.1 Benchmarks and Relative Performance 60
4.2.2 Profiling and Locating Bottlenecks 68
4.3 Summary 69

Part II JavaScript for Programmers 71

5. Functions 73
5.1 Defining Functions 73
5.1.1 Function Declaration 73
5.1.2 Function Expression 74
5.1.3 The Function Constructor 75
5.2 Calling Functions 77
5.2.1 The arguments Object 77
5.2.2 Formal Parameters and arguments 79
5.3 Scope and Execution Context 80
5.3.1 Execution Contexts 81
5.3.2 The Variable Object 81
5.3.3 The Activation Object 82
5.3.4 The Global Object 82
5.3.5 The Scope Chain 83
5.3.6 Function Expressions Revisited 84
5.4 The this Keyword 87
5.4.1 Implicitly Setting this 88
5.4.2 Explicitly Setting this 89
5.4.3 Using Primitives As this 89
5.5 Summary 91

6. Applied Functions and Closures 93
6.1 Binding Functions 93
6.1.1 Losing this: A Lightbox Example 93
6.1.2 Fixing this via an Anonymous Function 95
6.1.3 Function.prototype.bind 95
6.1.4 Binding with Arguments 97
6.1.5 Currying 99
6.2 Immediately Called Anonymous Functions 101
6.2.1 Ad Hoc Scopes 101
6.2.1.1 Avoiding the Global Scope 101
6.2.1.2 Simulating Block Scope 102
6.2.2 Namespaces 103
6.2.2.1 Implementing Namespaces 104
6.2.2.2 Importing Namespaces 106
6.3 Stateful Functions 107
6.3.1 Generating Unique Ids 107
6.3.2 Iterators 109
6.4 Memoization 112
6.5 Summary 115

7. Objects and Prototypal Inheritance 117
7.1 Objects and Properties 117
7.1.1 Property Access 118
7.1.2 The Prototype Chain 119
7.1.3 Extending Objects through the Prototype Chain 121
7.1.4 Enumerable Properties 122
7.1.4.1 Object.prototype.hasOwnProperty 124
7.1.5 Property Attributes 126
7.1.5.1 ReadOnly 126
7.1.5.2 DontDelete 126
7.1.5.3 DontEnum 126
7.2 Creating Objects with Constructors 130
7.2.1 prototype and [[Prototype]] 130
7.2.2 Creating Objects with new 131
7.2.3 Constructor Prototypes 132
7.2.3.1 Adding Properties to the Prototype 132
7.2.4 The Problem with Constructors 135
7.3 Pseudo-classical Inheritance 136
7.3.1 The Inherit Function 137
7.3.2 Accessing [[Prototype]] 138
7.3.3 Implementing super 139
7.3.3.1 The _super Method 140
7.3.3.2 Performance of the super Method 143
7.3.3.3 A _super Helper Function 143
7.4 Encapsulation and Information Hiding 145
7.4.1 Private Methods 145
7.4.2 Private Members and Privileged Methods 147
7.4.3 Functional Inheritance 148
7.4.3.1 Extending Objects 149
7.5 Object Composition and Mixins 150
7.5.1 The Object.create Method 151
7.5.2 The tddjs.extend Method 153
7.5.3 Mixins 157
7.6 Summary 158

8. ECMAScript 5th Edition 159
8.1 The Close Future of JavaScript 159
8.2 Updates to the Object Model 161
8.2.1 Property Attributes 161
8.2.2 Prototypal Inheritance 164
8.2.3 Getters and Setters 166
8.2.4 Making Use of Property Attributes 167
8.2.5 Reserved Keywords as Property Identifiers 170
8.3 Strict Mode 171
8.3.1 Enabling Strict Mode 171
8.3.2 Strict Mode Changes 172
8.3.2.1 No Implicit Globals 172
8.3.2.2 Functions 172
8.3.2.3 Objects, Properties, and Variables 174
8.3.2.4 Additional Restrictions 174
8.4 Various Additions and Improvements 174
8.4.1 Native JSON 175
8.4.2 Function.prototype.bind 175
8.4.3 Array Extras 175
8.5 Summary 176

9. Unobtrusive JavaScript 177
9.1 The Goal of Unobtrusive JavaScript 177
9.2 The Rules of Unobtrusive JavaScript 178
9.2.1 An Obtrusive Tabbed Panel 179
9.2.2 Clean Tabbed Panel Markup 181
9.2.3 TDD and Progressive Enhancement 182
9.3 Do Not Make Assumptions 183
9.3.1 Don’t Assume You Are Alone 183
9.3.1.1 How to Avoid 183
9.3.2 Don’t Assume Markup Is Correct 183
9.3.2.1 How to Avoid 184
9.3.3 Don’t Assume All Users Are Created Equal 184
9.3.3.1 How to Avoid 184
9.3.4 Don’t Assume Support 184
9.4 When Do the Rules Apply? 184
9.5 Unobtrusive Tabbed Panel Example 185
9.5.1 Setting Up the Test 186
9.5.2 The tabController Object 187
9.5.3 The activateTab Method 190
9.5.4 Using the Tab Controller 192
9.6 Summary 196

10. Feature Detection 197
10.1 Browser Sniffing 198
10.1.1 User Agent Sniffing 198
10.1.2 Object Detection 199
10.1.3 The State of Browser Sniffing 200
10.2 Using Object Detection for Good 200
10.2.1 Testing for Existence 201
10.2.2 Type Checking 201
10.2.3 Native and Host Objects 202
10.2.4 Sample Use Testing 204
10.2.5 When to Test 206
10.3 Feature Testing DOM Events 207
10.4 Feature Testing CSS Properties 208
10.5 Cross-Browser Event Handlers 210
10.6 Using Feature Detection 213
10.6.1 Moving Forward 213
10.6.2 Undetectable Features 214
10.7 Summary 214

Part III Real-World Test-Driven Development in JavaScript 217

11. The Observer Pattern 219
11.1 The Observer in JavaScript 220
11.1.1 The Observable Library 220
11.1.2 Setting up the Environment 221
11.2 Adding Observers 222
11.2.1 The First Test 222
11.2.1.1 Running the Test and Watching It Fail 222
11.2.1.2 Making the Test Pass 223
11.2.2 Refactoring 225
11.3 Checking for Observers 226
11.3.1 The Test 226
11.3.1.1 Making the Test Pass 227
11.3.1.2 Solving Browser Incompatibilities 228
11.3.2 Refactoring 229
11.4 Notifying Observers 230
11.4.1 Ensuring That Observers Are Called 230
11.4.2 Passing Arguments 231
11.5 Error Handling 232
11.5.1 Adding Bogus Observers 232
11.5.2 Misbehaving Observers 233
11.5.3 Documenting Call Order 234
11.6 Observing Arbitrary Objects 235
11.6.1 Making the Constructor Obsolete 236
11.6.2 Replacing the Constructor with an Object 239
11.6.3 Renaming Methods 240
11.7 Observing Arbitrary Events 241
11.7.1 Supporting Events in observe 241
11.7.2 Supporting Events in notify 243
11.8 Summary 246

12. Abstracting Browser Differences: Ajax 247
12.1 Test Driving a Request API 247
12.1.1 Discovering Browser Inconsistencies 248
12.1.2 Development Strategy 248
12.1.3 The Goal 248
12.2 Implementing the Request Interface 249
12.2.1 Project Layout 249
12.2.2 Choosing the Interface Style 250
12.3 Creating an XMLHttpRequest Object 250
12.3.1 The First Test 251
12.3.2 XMLHttpRequest Background 251
12.3.3 Implementing tddjs.ajax.create 253
12.3.4 Stronger Feature Detection 254
12.4 Making Get Requests 255
12.4.1 Requiring a URL 255
12.4.2 Stubbing the XMLHttpRequest Object 257
12.4.2.1 Manual Stubbing 257
12.4.2.2 Automating Stubbing 258
12.4.2.3 Improved Stubbing 261
12.4.2.4 Feature Detection and ajax.create 263
12.4.3 Handling State Changes 263
12.4.4 Handling the State Changes 265
12.4.4.1 Testing for Success 265
12.5 Using the Ajax API 269
12.5.1 The Integration Test 269
12.5.2 Test Results 270
12.5.3 Subtle Trouble Ahead 271
12.5.4 Local Requests 273
12.5.5 Testing Statuses 274
12.5.5.1 Further Status Code Tests 276
12.6 Making POST Requests 277
12.6.1 Making Room for Posts 277
12.6.1.1 Extracting ajax.request 278
12.6.1.2 Making the Method Configurable 278
12.6.1.3 Updating ajax.get 280
12.6.1.4 Introducing ajax.post 281
12.6.2 Sending Data 282
12.6.2.1 Encoding Data in ajax.request 283
12.6.2.2 Sending Encoded Data 284
12.6.2.3 Sending Data with GET Requests 285
12.6.3 Setting Request Headers 287
12.7 Reviewing the Request API 288
12.8 Summary 292

13. Streaming Data with Ajax and Comet 293
13.1 Polling for Data 294
13.1.1 Project Layout 294
13.1.2 The Poller: tddjs.ajax.poller 295
13.1.2.1 Defining the Object 296
13.1.2.2 Start Polling 296
13.1.2.3 Deciding the Stubbing Strategy 298
13.1.2.4 The First Request 299
13.1.2.5 The complete Callback 300
13.1.3 Testing Timers 303
13.1.3.1 Scheduling New Requests 304
13.1.3.2 Configurable Intervals 306
13.1.4 Configurable Headers and Callbacks 308
13.1.5 The One-Liner 311
13.2 Comet 314
13.2.1 Forever Frames 314
13.2.2 Streaming XMLHttpRequest 315
13.2.3 HTML5 315
13.3 Long Polling XMLHttpRequest 315
13.3.1 Implementing Long Polling Support 316
13.3.1.1 Stubbing Date 316
13.3.1.2 Testing with Stubbed Dates 317
13.3.2 Avoiding Cache Issues 319
13.3.3 Feature Tests 320
13.4 The Comet Client 321
13.4.1 Messaging Format 321
13.4.2 Introducing ajax.CometClient 323
13.4.3 Dispatching Data 323
13.4.3.1 Adding ajax.CometClient.dispatch 324
13.4.3.2 Delegating Data 324
13.4.3.3 Improved Error Handling 325
13.4.4 Adding Observers 327
13.4.5 Server Connection 329
13.4.5.1 Separating Concerns 334
13.4.6 Tracking Requests and Received Data 335
13.4.7 Publishing Data 338
13.4.8 Feature Tests 338
13.5 Summary 339

14. Server-Side JavaScript with Node.js 341
14.1 The Node.js Runtime 341
14.1.1 Setting up the Environment 342
14.1.1.1 Directory Structure 342
14.1.1.2 Testing Framework 343
14.1.2 Starting Point 343
14.1.2.1 The Server 343
14.1.2.2 The Startup Script 344
14.2 The Controller 345
14.2.1 CommonJS Modules 345
14.2.2 Defining the Module: The First Test 345
14.2.3 Creating a Controller 346
14.2.4 Adding Messages on POST 347
14.2.4.1 Reading the Request Body 348
14.2.4.2 Extracting the Message 351
14.2.4.3 Malicious Data 354
14.2.5 Responding to Requests 354
14.2.5.1 Status Code 354
14.2.5.2 Closing the Connection 355
14.2.6 Taking the Application for a Spin 356
14.3 Domain Model and Storage 358
14.3.1 Creating a Chat Room 358
14.3.2 I/O in Node 358
14.3.3 Adding Messages 359
14.3.3.1 Dealing with Bad Data 359
14.3.3.2 Successfully Adding Messages 361
14.3.4 Fetching Messages 363
14.3.4.1 The getMessagesSince Method 363
14.3.4.2 Making addMessage Asynchronous 365
14.4 Promises 367
14.4.1 Refactoring addMessage to Use Promises 367
14.4.1.1 Returning a Promise 368
14.4.1.2 Rejecting the Promise 369
14.4.1.3 Resolving the Promise 370
14.4.2 Consuming Promises 371
14.5 Event Emitters 372
14.5.1 Making chatRoom an Event Emitter 372
14.5.2 Waiting for Messages 375
14.6 Returning to the Controller 378
14.6.1 Finishing the post Method 378
14.6.2 Streaming Messages with GET 380
14.6.2.1 Filtering Messages with Access Tokens 381
14.6.2.2 The respond Method 382
14.6.2.3 Formatting Messages 383
14.6.2.4 Updating the Token 385
14.6.3 Response Headers and Body 386
14.7 Summary 387

15. TDD and DOM Manipulation: The Chat Client 389
15.1 Planning the Client 389
15.1.1 Directory Structure 390
15.1.2 Choosing the Approach 390
15.1.2.1 Passive View 391
15.1.2.2 Displaying the Client 391
15.2 The User Form 392
15.2.1 Setting the View 392
15.2.1.1 Setting Up the Test Case 392
15.2.1.2 Adding a Class 393
15.2.1.3 Adding an Event Listener 394
15.2.2 Handling the Submit Event 398
15.2.2.1 Aborting the Default Action 398
15.2.2.2 Embedding HTML in Tests 400
15.2.2.3 Getting the Username 401
15.2.2.4 Notifying Observers of the User 403
15.2.2.5 Removing the Added Class 406
15.2.2.6 Rejecting Empty Usernames 406
15.2.3 Feature Tests 407
15.3 Using the Client with the Node.js Backend 408
15.4 The Message List 411
15.4.1 Setting the Model 411
15.4.1.1 Defining the Controller and Method 411
15.4.1.2 Subscribing to Messages 412
15.4.2 Setting the View 414
15.4.3 Adding Messages 416
15.4.4 Repeated Messages from Same User 418
15.4.5 Feature Tests 420
15.4.6 Trying it Out 420
15.5 The Message Form 422
15.5.1 Setting up the Test 422
15.5.2 Setting the View 422
15.5.2.1 Refactoring: Extracting the Common Parts 423
15.5.2.2 Setting messageFormController’s View 424
15.5.3 Publishing Messages 425
15.5.4 Feature Tests 428
15.6 The Final Chat Client 429
15.6.1 Finishing Touches 430
15.6.1.1 Styling the Application 430
15.6.1.2 Fixing the Scrolling 431
15.6.1.3 Clearing the Input Field 432
15.6.2 Notes on Deployment 433
15.7 Summary 434

Part IV Testing Patterns 437

16. Mocking and Stubbing 439
16.1 An Overview of Test Doubles 439
16.1.1 Stunt Doubles 440
16.1.2 Fake Object 440
16.1.3 Dummy Object 441
16.2 Test Verification 441
16.2.1 State Verification 442
16.2.2 Behavior Verification 442
16.2.3 Implications of Verification Strategy 443
16.3 Stubs 443
16.3.1 Stubbing to Avoid Inconvenient Interfaces 444
16.3.2 Stubbing to Force Certain Code Paths 444
16.3.3 Stubbing to Cause Trouble 445
16.4 Test Spies 445
16.4.1 Testing Indirect Inputs 446
16.4.2 Inspecting Details about a Call 446
16.5 Using a Stub Library 447
16.5.1 Creating a Stub Function 448
16.5.2 Stubbing a Method 448
16.5.3 Built-in Behavior Verification 451
16.5.4 Stubbing and Node.js 452
16.6 Mocks 453
16.6.1 Restoring Mocked Methods 453
16.6.2 Anonymous Mocks 454
16.6.3 Multiple Expectations 455
16.6.4 Expectations on the this Value 456
16.7 Mocks or Stubs? 457
16.8 Summary 458

17. Writing Good Unit Tests 461
17.1 Improving Readability 462
17.1.1 Name Tests Clearly to Reveal Intent 462
17.1.1.1 Focus on Scannability 462
17.1.1.2 Breaking Free of Technical Limitations 463
17.1.2 Structure Tests in Setup, Exercise, and Verify Blocks 464
17.1.3 Use Higher-Level Abstractions to Keep Tests Simple 465
17.1.3.1 Custom Assertions: Behavior Verification 465
17.1.3.2 Domain Specific Test Helpers 466
17.1.4 Reduce Duplication, Not Clarity 467
17.2 Tests as Behavior Specification 468
17.2.1 Test One Behavior at a Time 468
17.2.2 Test Each Behavior Only Once 469
17.2.3 Isolate Behavior in Tests 470
17.2.3.1 Isolation by Mocking and Stubbing 470
17.2.3.2 Risks Introduced by Mocks and Stubs 471
17.2.3.3 Isolation by Trust 472
17.3 Fighting Bugs in Tests 473
17.3.1 Run Tests Before Passing Them 473
17.3.2 Write Tests First 473
17.3.3 Heckle and Break Code 474
17.3.4 Use JsLint 474
17.4 Summary 475

Be the first to comment

Leave a Reply

Your email address will not be published.

*