CINXE.COM
Google Testing Blog: June 2008
<!DOCTYPE html> <html class='v2 list-page' dir='ltr' itemscope='' itemtype='http://schema.org/Blog' lang='en' xmlns='http://www.w3.org/1999/xhtml' xmlns:b='http://www.google.com/2005/gml/b' xmlns:data='http://www.google.com/2005/gml/data' xmlns:expr='http://www.google.com/2005/gml/expr'> <head> <link href='https://www.blogger.com/static/v1/widgets/3566091532-css_bundle_v2.css' rel='stylesheet' type='text/css'/> <title> Google Testing Blog: June 2008 </title> <meta content='width=device-width, height=device-height, minimum-scale=1.0, initial-scale=1.0, user-scalable=0' name='viewport'/> <meta content='IE=Edge' http-equiv='X-UA-Compatible'/> <meta content='Google Testing Blog' property='og:title'/> <meta content='en_US' property='og:locale'/> <meta content='https://testing.googleblog.com/2008/06/' property='og:url'/> <meta content='Google Testing Blog' property='og:site_name'/> <!-- Twitter Card properties --> <meta content='Google Testing Blog' property='og:title'/> <meta content='summary' name='twitter:card'/> <meta content='@googletesting' name='twitter:creator'/> <link href='https://fonts.googleapis.com/css?family=Roboto:400italic,400,500,500italic,700,700italic' rel='stylesheet' type='text/css'/> <link href='https://fonts.googleapis.com/icon?family=Material+Icons' rel='stylesheet'/> <script src='https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js' type='text/javascript'></script> <!-- End --> <style id='page-skin-1' type='text/css'><!-- /* <Group description="Header Color" selector="header"> <Variable name="header.background.color" description="Header Background" type="color" default="#ffffff"/> </Group> */ .header-outer { border-bottom: 1px solid #e0e0e0; background: #ffffff; } html, .Label h2, #sidebar .rss a, .BlogArchive h2, .FollowByEmail h2.title, .widget .post h2 { font-family: Roboto, sans-serif; } .plusfollowers h2.title, .post h2.title, .widget h2.title { font-family: Roboto, sans-serif; } .widget-item-control { height: 100%; } .widget.Header, #header { position: relative; height: 100%; width: 100%; } } .widget.Header .header-logo1 { float: left; margin-right: 15px; padding-right: 15px; border-right: 1px solid #ddd; } .header-title h2 { color: rgba(0,0,0,.54); display: inline-block; font-size: 40px; font-family: Roboto, sans-serif; font-weight: normal; line-height: 48px; vertical-align: top; } .header-inner { background-repeat: no-repeat; background-position: right 0px; } .post-author, .byline-author { font-size: 14px; font-weight: normal; color: #757575; color: rgba(0,0,0,.54); } .post-content .img-border { border: 1px solid rgb(235, 235, 235); padding: 4px; } .header-title a { text-decoration: none !important; } pre { border: 1px solid #bbbbbb; margin-top: 1em 0 0 0; padding: 0.99em; overflow-x: auto; overflow-y: auto; } pre, code { font-size: 9pt; background-color: #fafafa; line-height: 125%; font-family: monospace; } pre, code { color: #060; font: 13px/1.54 "courier new",courier,monospace; } .header-left .header-logo1 { width: 128px !important; } .header-desc { line-height: 20px; margin-top: 8px; } .fb-custom img, .twitter-custom img, .gplus-share img { cursor: pointer; opacity: 0.54; } .fb-custom img:hover, .twitter-custom img:hover, .gplus-share img:hover { opacity: 0.87; } .fb-like { width: 80px; } .post .share { float: right; } #twitter-share{ border: #CCC solid 1px; border-radius: 3px; background-image: -webkit-linear-gradient(top,#ffffff,#dedede); } .twitter-follow { background: url(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSPSElBOH0lQ-yG1UMSLWe_pq9gZ9DT-0xhhjwadPeQt1WAHCnDYvERUcHBadwN6NcdtZCJu-F0fLqO6_PnV2iWDxnun1R_ii8saOztKUI6GA6zc2FNkjkcfTDlPzaINdbYhPw7Q/s1600/twitter-bird.png) no-repeat left center; padding-left: 18px; font: normal normal normal 11px/18px 'Helvetica Neue',Arial,sans-serif; font-weight: bold; text-shadow: 0 1px 0 rgba(255,255,255,.5); cursor: pointer; margin-bottom: 10px; } .twitter-fb { padding-top: 2px; } .fb-follow-button { background: -webkit-linear-gradient(#4c69ba, #3b55a0); background: -moz-linear-gradient(#4c69ba, #3b55a0); background: linear-gradient(#4c69ba, #3b55a0); border-radius: 2px; height: 18px; padding: 4px 0 0 3px; width: 57px; border: #4c69ba solid 1px; } .fb-follow-button a { text-decoration: none !important; text-shadow: 0 -1px 0 #354c8c; text-align: center; white-space: nowrap; font-size: 11px; color: white; vertical-align: top; } .fb-follow-button a:visited { color: white; } .fb-follow { padding: 0px 5px 3px 0px; width: 14px; vertical-align: bottom; } .gplus-wrapper { margin-top: 3px; display: inline-block; vertical-align: top; } .twitter-custom, .gplus-share { margin-right: 12px; } .fb-follow-button{ margin: 10px auto; } /** CUSTOM CODE **/ /* Make the page title smaller */ .header-inner { height: 120px !important; } /* Make the post titles look like the links that they are */ .post .title a { color: #4184F3 !important; } /* Set a normal line height in post text */ .post .post-content { line-height: 1.4 !important; } .post .post-content li { line-height: 1.4 !important; } /* Custom table class used in some posts */ .my-bordered-table { border-collapse: collapse; border: 1px solid black; } .my-bordered-table th, .my-bordered-table td { border: 1px solid black; padding: 5px; } --></style> <style id='template-skin-1' type='text/css'><!-- .header-outer { clear: both; } .header-inner { margin: auto; padding: 0px; } .footer-outer { background: #f5f5f5; clear: both; margin: 0; } .footer-inner { margin: auto; padding: 0px; } .footer-inner-2 { /* Account for right hand column elasticity. */ max-width: calc(100% - 248px); } .google-footer-outer { clear: both; } .cols-wrapper, .google-footer-outer, .footer-inner, .header-inner { max-width: 978px; margin-left: auto; margin-right: auto; } .cols-wrapper { margin: auto; clear: both; margin-top: 60px; margin-bottom: 60px; overflow: hidden; } .col-main-wrapper { float: left; width: 100%; } .col-main { margin-right: 278px; max-width: 660px; } .col-right { float: right; width: 248px; margin-left: -278px; } /* Tweaks for layout mode. */ body#layout .google-footer-outer { display: none; } body#layout .header-outer, body#layout .footer-outer { background: none; } body#layout .header-inner { height: initial; } body#layout .cols-wrapper { margin-top: initial; margin-bottom: initial; } --></style> <!-- start all head --> <meta content='text/html; charset=UTF-8' http-equiv='Content-Type'/> <meta content='blogger' name='generator'/> <link href='https://testing.googleblog.com/favicon.ico' rel='icon' type='image/x-icon'/> <link href='https://testing.googleblog.com/2008/06/' rel='canonical'/> <link rel="alternate" type="application/atom+xml" title="Google Testing Blog - Atom" href="https://testing.googleblog.com/feeds/posts/default" /> <link rel="alternate" type="application/rss+xml" title="Google Testing Blog - RSS" href="https://testing.googleblog.com/feeds/posts/default?alt=rss" /> <link rel="service.post" type="application/atom+xml" title="Google Testing Blog - Atom" href="https://www.blogger.com/feeds/15045980/posts/default" /> <!--Can't find substitution for tag [blog.ieCssRetrofitLinks]--> <meta content='https://testing.googleblog.com/2008/06/' property='og:url'/> <meta content='Google Testing Blog' property='og:title'/> <meta content='' property='og:description'/> <!-- end all head --> <base target='_self'/> <style> html { font-family: Roboto, sans-serif; -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; } body { padding: 0; /* This ensures that the scroll bar is always present, which is needed */ /* because content render happens after page load; otherwise the header */ /* would "bounce" in-between states. */ min-height: 150%; } h2 { font-size: 20px; } h1, h2, h3, h4, h5 { line-height: 2em; } html, h4, h5, h6 { font-size: 17px; } h3 { font-size: 18px !important; } a, a:visited { color: #4184F3; text-decoration: none; } a:focus, a:hover, a:active { text-decoration: none; } .Header { margin-top: 15px; } .Header h1 { font-size: 32px; font-weight: 300; line-height: 32px; height: 42px; } .header-inner .Header .titlewrapper { padding: 0; margin-top: 30px; } .header-inner .Header .descriptionwrapper { padding: 0; margin: 0; } .cols-wrapper { margin-top: 56px; } .header-outer, .cols-wrapper, .footer-outer, .google-footer-outer { padding: 0 60px; } .header-inner { height: 256px; position: relative; } html, .header-inner a { color: #212121; color: rgba(0,0,0,.87); } .header-inner .google-logo { display: inline-block; background-size: contain; z-index: 1; height: 46px; overflow: hidden; margin-top: 4px; margin-right: 8px; } .header-left { position: absolute; top: 50%; -webkit-transform: translateY(-50%); transform: translateY(-50%); margin-top: 12px; width: 100%; } .google-logo { margin-left: -4px; } #google-footer { position: relative; font-size: 13px; list-style: none; text-align: right; } #google-footer a { color: #444; } #google-footer ul { margin: 0; padding: 0; height: 144px; line-height: 144px; } #google-footer ul li { display: inline; } #google-footer ul li:before { color: #999; content: "\00b7"; font-weight: bold; margin: 5px; } #google-footer ul li:first-child:before { content: ''; } #google-footer .google-logo-dark { left: 0; margin-top: -16px; position: absolute; top: 50%; } /** Sitemap links. **/ .footer-inner-2 { font-size: 14px; padding-top: 42px; padding-bottom: 74px; } .footer-inner-2 .HTML h2 { color: #212121; color: rgba(0,0,0,.87); font-size: 14px; font-weight: 500; padding-left: 0; margin: 10px 0; } .footer-inner-2 .HTML ul { font-weight: normal; list-style: none; padding-left: 0; } .footer-inner-2 .HTML li { line-height: 24px; padding: 0; } .footer-inner-2 li a { color: rgba(65,132,243,.87); } /** Archive widget. **/ .BlogArchive { font-size: 13px; font-weight: normal; } .BlogArchive .widget-content { display: none; } .BlogArchive h2, .Label h2 { color: #4184F3; text-decoration: none; } .BlogArchive .hierarchy li { display: inline-block; } /* Specificity needed here to override widget CSS defaults. */ .BlogArchive #ArchiveList ul li, .BlogArchive #ArchiveList ul ul li { padding-left: 0; text-indent: 0; } .BlogArchive .intervalToggle { cursor: pointer; } .BlogArchive .expanded .intervalToggle .new-toggle { -ms-transform: rotate(180deg); transform: rotate(180deg); } .BlogArchive .new-toggle { float: right; padding-top: 3px; opacity: 0.87; } #ArchiveList { text-transform: uppercase; } #ArchiveList .expanded > ul:last-child { margin-bottom: 16px; } #ArchiveList .archivedate { width: 100%; } /* Months */ .BlogArchive .items { max-width: 150px; margin-left: -4px; } .BlogArchive .expanded .items { margin-bottom: 10px; overflow: hidden; } .BlogArchive .items > ul { float: left; height: 32px; } .BlogArchive .items a { padding: 0 4px; } .Label { font-size: 13px; font-weight: normal; } .sidebar-icon { display: inline-block; width: 24px; height: 24px; vertical-align: middle; margin-right: 12px; margin-top: -1px } .Label a { margin-right: 4px; } .Label .widget-content { display: none; } .FollowByEmail { font-size: 13px; font-weight: normal; } .FollowByEmail h2 { background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAALCAYAAACZIGYHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAUBJREFUeNrMkSGLAlEUhb+ZB4JFi8mx2cz+ApvhRUGTcUCrNqNJDYIi+DO0GUwmQXDK2DSIoGgZcSaIjDrzwrK4ssvChj1w0733O+fdp+m6PozH4yQSCfb7Pa7r8pOi0SjJZBLP8zgej4gAIMvlMuPxmADIYrHger1+C6lUKmo+NJ/NZojb7SZDWiwWo1qtks1msW2bw+HwZdkwDHq9HvV6nel0SqvVYrvdIh6Ph3Qch+VyqRYLhQJSSjRNw7IsfN9XgGKxSLfbJZfL0e/3aTabrFYr7vc7IujLcOh8PqunrNdr0uk0pVKJVCpFJBJRgEajweVyod1uMxgM2O12BAGUgRbU8DV2JpOhVquRz+cRQii3+XxOp9NRN3jVR5LPOp1OjEYjlSL8hclkgmmabDabt4d+m+S30vkD/R/IU4ABAPTZgnZdmG/PAAAAAElFTkSuQmCC"); background-repeat: no-repeat; background-position: 0 50%; text-indent: 30px; } .FollowByEmail .widget-content { display: none; } .searchBox input { border: 1px solid #eee; color: #212121; color: rgba(0,0,0,.87); font-size: 14px; padding: 8px 8px 8px 40px; width: 164px; font-family: Roboto, sans-serif; background: url("https://www.gstatic.com/images/icons/material/system/1x/search_grey600_24dp.png") 8px center no-repeat; } .searchBox ::-webkit-input-placeholder { /* WebKit, Blink, Edge */ color: rgba(0,0,0,.54); } .searchBox :-moz-placeholder { /* Mozilla Firefox 4 to 18 */ color: #000; opacity: 0.54; } .searchBox ::-moz-placeholder { /* Mozilla Firefox 19+ */ color: #000; opacity: 0.54; } .searchBox :-ms-input-placeholder { /* Internet Explorer 10-11 */ color: #757575; } .widget-item-control { margin-top: 0px; } .section { margin: 0; padding: 0; } #sidebar-top { border: 1px solid #eee; } #sidebar-top > div { margin: 16px 0; } .widget ul { line-height: 1.6; } /*main post*/ .post { margin-bottom:30px; } #main .post .title { margin: 0; } #main .post .title a { color: #212121; color: rgba(0,0,0,.87); font-weight: normal; font-size: 24px; } #main .post .title a:hover { text-decoration:none; color:#4184F3; } .message, #main .post .post-header { margin: 0; padding: 0; } #main .post .post-header .caption, #main .post .post-header .labels-caption, #main .post .post-footer .caption, #main .post .post-footer .labels-caption { color: #444; font-weight: 500; } #main .tr-caption-container td { text-align: left; } #main .post .tr-caption { color: #757575; color: rgba(0,0,0,.54); display: block; max-width: 560px; padding-bottom: 20px; } #main .post .tr-caption-container { line-height: 24px; margin: -1px 0 0 0 !important; padding: 4px 0; text-align: left; } #main .post .post-header .published{ font-size:11px; font-weight:bold; } .post-header .publishdate { font-size: 17px; font-weight:normal; color: #757575; color: rgba(0,0,0,.54); } #main .post .post-footer{ font-size:12px; padding-bottom: 21px; } .label-footer { margin-bottom: 12px; margin-top: 12px; } .comment-img { margin-right: 16px; opacity: 0.54; vertical-align: middle; } #main .post .post-header .published { margin-bottom: 40px; margin-top: -2px; } .post .post-content { color: #212121; color: rgba(0,0,0,.87); font-size: 17px; margin: 25px 0 36px 0; line-height: 32px; word-wrap: break-word; } .post-body .post-content ul, .post-body .post-content ol { margin: 16px 0; padding: 0 48px; } .post-summary { display: none; } /* Capture section headers. */ .post-content br + br + b, .post-content .space + .space + b, .post-content .separator + b { display: inline-block; margin-bottom: 8px; margin-top: 24px; } .post-content li { line-height: 32px; } /* Override all post images/videos to left align. */ .post-content .separator, .post-content > div { text-align: left; } .post-content .separator > a, .post-content .separator > span { margin-left: 0 !important; } .post-content img { max-width: 100%; } .post-content .tr-caption-container img { margin-bottom: 12px; } .post-content iframe, .post-content embed { max-width: 100%; } .post-content .carousel-container { margin-bottom: 48px; } #main .post-content b { font-weight: 500; } /* These are the main paragraph spacing tweaks. */ #main .post-content br { content: ' '; display: block; padding: 4px; } .post-content .space { display: block; height: 8px; } .post-content iframe + .space, .post-content iframe + br { padding: 0 !important; } #main .post .jump-link { margin-bottom:10px; } .post-content img, .post-content iframe { margin: 30px 0 20px 0; } .post-content > img:first-child, .post-content > iframe:first-child { margin-top: 0; } .col-right .section { padding: 0 16px; } #aside { background:#fff; border:1px solid #eee; border-top: 0; } #aside .widget { margin:0; } #aside .widget h2, #ArchiveList .toggle + a.post-count-link { color: #212121; color: rgba(0,0,0,.87); font-weight: 400 !important; margin: 0; } #ArchiveList .toggle { float: right; } #ArchiveList .toggle .material-icons { padding-top: 4px; } #sidebar .tab { cursor: pointer; } #sidebar .tab .arrow { display: inline-block; float: right; } #sidebar .tab .icon { display: inline-block; vertical-align: top; height: 24px; width: 24px; margin-right: 13px; margin-left: -1px; margin-top: 1px; color: #757575; color: rgba(0,0,0,.54); } #sidebar .widget-content > :first-child { padding-top: 8px; } #sidebar .active .tab .arrow { -ms-transform: rotate(180deg); transform: rotate(180deg); } #sidebar .arrow { color: #757575; color: rgba(0,0,0,.54); } #sidebar .widget h2 { font-size: 14px; line-height: 24px; display: inline-block; } #sidebar .widget .BlogArchive { padding-bottom: 8px; } #sidebar .widget { border-bottom: 1px solid #eee; box-shadow: 0px 1px 0 white; margin-bottom: 0; padding: 14px 0; min-height: 20px; } #sidebar .widget:last-child { border-bottom: none; box-shadow: none; margin-bottom: 0; } #sidebar ul { margin: 0; padding: 0; } #sidebar ul li { list-style:none; padding:0; } #sidebar ul li a { line-height: 32px; } #sidebar .archive { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAYCAYAAADzoH0MAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAE1JREFUeNpiNDY23s9AAWBioBCwYBM8c+YMVsUmJibEGYBNMS5DaeMFfDYSZQA2v9I3FrB5AZeriI4FmnrBccCT8mhmGs1MwyAzAQQYAKEWG9zm9QFEAAAAAElFTkSuQmCC"); height: 24px; line-height: 24px; padding-left: 30px; } #sidebar .labels { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAYAAAA7bUf6AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAUxJREFUeNpiNDY23s9AAMycOfM7UF05kHkZmzwTMkdSUhKrIcXFxZy3bt3qBjIN8RrS09PDsHnzZjCNDr58+cKQlpbGDjSoHcg1w2oIyAUODg5gARCNzUVIBrUCuVYYhjx//pzhwIEDYAEQDeJjA1CDWIAGNQK59jBxRuSABbkAlwHIgIeHh2HWrFn/1NTU2oDcvSgBS4wBSC5iArqoCsj1YGIgEyAZVMoEchqlBjEB/cZAiUHg2AEGznpKDAImxOeM////B4VLKtBvEUCngZ1ILKivr3/u6+ubBzJAGZQ9gC5aQoqLgAY8BhkAZL4BuQQkxgXE34A4BuiiZEIuAhrwEGhAEZD5DpzYoIaA2UAM4kQADUrHZRDUgAIg8wO2XAwzbQXQa5OweQ1owB10AyA6gS7BgX1u3ry5397eHow3bdo0EyjGi00tQIABANPgyAH1q1eaAAAAAElFTkSuQmCC"); height: 20px; line-height: 20px; padding-left: 30px; } #sidebar .rss a { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAX5JREFUeNqsVDGSgkAQHL2rIiIikohIc/EBRkbwAIwuwgfwAXiAD9AHSI7kEkECRCb6AIyINDLx7K0aa6kT7uq0q7YYtnZ7umdnt7darXbr9Zpegeu61DNNc0dvwCcH4/GYJpMJnc9nOhwOVJbl/4hAAokMECZJQtvt9k+kH7qufyEYDAakqqqYxFdRFBqNRmTbNg2HQ0rTlK7XayvR0xqBdDqdkuM4dE/0ULhYLOh4PHYrknG5XGi/31MYhuL/nkwonM1mlGUZ1XXdrsiyLGEDhY7juJEZ1u5tIixDGdYhmYw+B7CAzPP5nDabjdgIAgCksMX1832/3drtdqPT6SQWapomiGEFNkDEdpDMMAzK81ys/7XYy+XyoQgq2WoURSIJ2iIIgp/WZCCTvFm2wgeAU31aI3Q2GhIDMeB53qPYPIcm5VrxXIOIOxsDMStjVawAc1VViRgN22lNBiuQN3GR+SY07hpOoStmFQAKXRRFY93bnpG+fONfedi+BRgAbkS8Fxp7QQIAAAAASUVORK5CYII="); } #sidebar .subscription a { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAALCAYAAACZIGYHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAUBJREFUeNrMkSGLAlEUhb+ZB4JFi8mx2cz+ApvhRUGTcUCrNqNJDYIi+DO0GUwmQXDK2DSIoGgZcSaIjDrzwrK4ssvChj1w0733O+fdp+m6PozH4yQSCfb7Pa7r8pOi0SjJZBLP8zgej4gAIMvlMuPxmADIYrHger1+C6lUKmo+NJ/NZojb7SZDWiwWo1qtks1msW2bw+HwZdkwDHq9HvV6nel0SqvVYrvdIh6Ph3Qch+VyqRYLhQJSSjRNw7IsfN9XgGKxSLfbJZfL0e/3aTabrFYr7vc7IujLcOh8PqunrNdr0uk0pVKJVCpFJBJRgEajweVyod1uMxgM2O12BAGUgRbU8DV2JpOhVquRz+cRQii3+XxOp9NRN3jVR5LPOp1OjEYjlSL8hclkgmmabDabt4d+m+S30vkD/R/IU4ABAPTZgnZdmG/PAAAAAElFTkSuQmCC"); } #sidebar-bottom { background: #f5f5f5; border-top:1px solid #eee; } #sidebar-bottom .widget { border-bottom: 1px solid #e0e0e0; padding: 15px 0; text-align: center; } #sidebar-bottom > div:last-child { border-bottom: 0; } #sidebar-bottom .text { line-height: 20px; } /* Home, forward, and backward pagination. */ .blog-pager { border-top : 1px #e0e0e0 solid; padding-top: 10px; margin-top: 15px; text-align: right !important; } #blog-pager { margin-botom: 0; margin-top: -14px; padding: 16px 0 0 0; } #blog-pager a { display: inline-block; } .blog-pager i.disabled { opacity: 0.2 !important; } .blog-pager i { color: black; margin-left: 16px; opacity: 0.54; } .blog-pager i:hover, .blog-pager i:active { opacity: 0.87; } #blog-pager-older-link, #blog-pager-newer-link { float: none; } .gplus-profile { background-color: #fafafa; border: 1px solid #eee; overflow: hidden; width: 212px; } .gplus-profile-inner { margin-left: -1px; margin-top: -1px; } /* Sidebar follow buttons. */ .followgooglewrapper { padding: 12px 0 0 0; } .loading { visibility: hidden; } .detail-page .post-footer .cmt_iframe_holder { padding-top: 40px !important; } /** Desktop **/ @media (max-width: 900px) { .col-right { display: none; } .col-main { margin-right: 0; min-width: initial; } .footer-outer { display: none; } .cols-wrapper { min-width: initial; } .google-footer-outer { background-color: #f5f5f5; } } /** Tablet **/ @media (max-width: 712px) { .header-outer, .cols-wrapper, .footer-outer, .google-footer-outer { padding: 0 40px; } } /* An extra breakpoint accommodating for long blog titles. */ @media (max-width: 600px) { .header-left { height: 100%; position: initial; top: inherit; margin-top: 0; -webkit-transform: initial; transform: initial; } .header-title { margin-top: 18px; } .header-inner { height: auto; margin-bottom: 32px; margin-top: 32px; } .header-desc { margin-top: 12px; } .header-inner .google-logo { height: 40px; margin-top: 3px; } .header-inner .google-logo img { height: 42px; } .header-title h2 { font-size: 32px; line-height: 40px; } } /** Mobile/small desktop window; also landscape. **/ @media (max-width: 480px), (max-height: 480px) { .header-outer, .cols-wrapper, .footer-outer, .google-footer-outer { padding: 0 16px; } .cols-wrapper { margin-top: 0; } .post-header .publishdate, .post .post-content { font-size: 16px; } .post .post-content { line-height: 28px; margin-bottom: 30px; } .post { margin-top: 30px; } .byline-author { display: block; font-size: 12px; line-height: 24px; margin-top: 6px; } #main .post .title a { font-weight: 500; color: #4c4c4c; color: rgba(0,0,0,.70); } #main .post .post-header { padding-bottom: 12px; } #main .post .post-header .published { margin-bottom: -8px; margin-top: 3px; } .post .read-more { display: block; margin-top: 14px; } .post .tr-caption { font-size: 12px; } #main .post .title a { font-size: 20px; line-height: 30px; } .post-content iframe { /* iframe won't keep aspect ratio when scaled down. */ max-height: 240px; } .post-content .separator img, .post-content .tr-caption-container img, .post-content iframe { margin-left: -16px; max-width: inherit; width: calc(100% + 32px); } .post-content table, .post-content td { width: 100%; } #blog-pager { margin: 0; padding: 16px 0; } /** List page tweaks. **/ .list-page .post-original { display: none; } .list-page .post-summary { display: block; } .list-page .comment-container { display: none; } .list-page #blog-pager { padding-top: 0; border: 0; margin-top: -8px; } .list-page .label-footer { display: none; } .list-page #main .post .post-footer { border-bottom: 1px solid #eee; margin: -16px 0 0 0; padding: 0 0 20px 0; } .list-page .post .share { display: none; } /** Detail page tweaks. **/ .detail-page .post-footer .cmt_iframe_holder { padding-top: 32px !important; } .detail-page .label-footer { margin-bottom: 0; } .detail-page #main .post .post-footer { padding-bottom: 0; } .detail-page #comments { display: none; } } [data-about-pullquote], [data-is-preview], [data-about-syndication] { display: none; } </style> <noscript> <style> .loading { visibility: visible }</style> </noscript> <!-- Google tag (gtag.js) --> <script async='true' src='https://www.googletagmanager.com/gtag/js?id=G-838ZCPQWM6'></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-838ZCPQWM6'); </script> <link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=15045980&zx=1da02fdc-f393-4bba-bcc4-96fe879b4516' media='none' onload='if(media!='all')media='all'' rel='stylesheet'/><noscript><link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=15045980&zx=1da02fdc-f393-4bba-bcc4-96fe879b4516' rel='stylesheet'/></noscript> <meta name='google-adsense-platform-account' content='ca-host-pub-1556223355139109'/> <meta name='google-adsense-platform-domain' content='blogspot.com'/> </head> <body> <script type='text/javascript'> //<![CDATA[ var axel = Math.random() + ""; var a = axel * 10000000000000; document.write('<iframe src="https://2542116.fls.doubleclick.net/activityi;src=2542116;type=gblog;cat=googl0;ord=ord=' + a + '?" width="1" height="1" frameborder="0" style="display:none"></iframe>'); //]]> </script> <noscript> <img alt='' height='1' src='https://ad.doubleclick.net/ddm/activity/src=2542116;type=gblog;cat=googl0;ord=1?' width='1'/> </noscript> <!-- Header --> <div class='header-outer'> <div class='header-inner'> <div class='section' id='header'><div class='widget Header' data-version='1' id='Header1'> <div class='header-left'> <div class='header-title'> <a class='google-logo' href='https://testing.googleblog.com/'> <img height='50' src='https://www.gstatic.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png'/> </a> <a href='/.'> <h2> Testing Blog </h2> </a> </div> <div class='header-desc'> </div> </div> </div></div> </div> </div> <!-- all content wrapper start --> <div class='cols-wrapper loading'> <div class='col-main-wrapper'> <div class='col-main'> <div class='section' id='main'><div class='widget Blog' data-version='1' id='Blog1'> <div class='post' data-id='4591414625061290830' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://testing.googleblog.com/2008/06/defeat-static-cling.html' itemprop='url' title='TotT: Defeat "Static Cling"'> TotT: Defeat "Static Cling" </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Thursday, June 26, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> You're pair programming and, as many brilliant people are apt to do, talking out loud. "I'll make a mock, inject it, and rerun the test. It should pa- ...D'OH" Your partner notices the exception <i>"ConnectionFactory not initialized"</i>. "What?" she says, "Something is using the database? Dang, and this was supposed to be a small test."<br /> <br /> Upon inspection you find that your class is calling a <b><span style="color: maroon;">static</span></b> method on some other class. You've got <b><span style="color: maroon;">Static Cling</span></b>! If you're (ab)using a data persistence layer that generates code which relies on static methods, <i>and weren't careful</i>, your code might look something like this:<br /> <br /> <div style="background: #e6f5ff none repeat scroll 0% 50%; border: 1px solid #808080; margin-bottom: 0pt; margin-left: 0.39in; margin-right: 0.39in; padding: 0.1in;"> <span style="font-family: courier new, monospace; font-size: 100%;">public class MyObject {</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> public int doSomething(int id) {</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> return TheirEntity.selectById(id).getSomething();</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> }</span><br /><span style="font-family: courier new, monospace; font-size: 100%;">}</span></div> <br /> <br /> As a result, you can't call doSomething without calling <span style="font-family: Courier New, monospace;">TheirEntity</span>'s static method. This code is hard to test because static methods are <b><span style="color: maroon;">impossible</span></b> to mock in Java.<br /> <br /> So, how do you get rid of this form of Static Cling and get that small test to pass? You can use a technique sometimes known as the <b><span style="color: maroon;">Repository Pattern</span></b>, a form of Abstract Factory. Create an interface and an implementation with the unmockable static method calls:<br /> <br /> <div style="background: #e6f5ff none repeat scroll 0% 50%; border: 1px solid #808080; margin-bottom: 0pt; margin-left: 0.39in; margin-right: 0.39in; padding: 0.1in;"> <span style="font-family: courier new, monospace; font-size: 100%;">interface TheirEntityRepository {</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> TheirEntity selectById(int id);</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> // other static methods on TheirEntity can be</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> // represented here too</span><br /><span style="font-family: courier new, monospace; font-size: 100%;">}</span><br /><span style="font-family: courier new, monospace; font-size: 100%;">public class TheirEntityStaticRepository</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> implements TheirEntityRepository {</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> public TheirEntity selectById(int id) { // non-static</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> return TheirEntity.selectById(id); // calls static method</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> }</span><br /><span style="font-family: courier new, monospace; font-size: 100%;">}</span></div> <br /> <br /> Next, inject a <span style="font-family: Courier New, monospace;">TheirEntityRepository</span> into <span style="font-family: Courier New, monospace;">MyObject</span> and use it instead of calls to the static method:<br /> <br /> <div style="background: #e6f5ff none repeat scroll 0% 50%; border: 1px solid #808080; margin-bottom: 0pt; margin-left: 0.39in; margin-right: 0.39in; padding: 0.1in;"> <span style="font-family: courier new, monospace; font-size: 100%;">public class MyObject {</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> private final TheirEntityRepository repository;</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> public MyEntity(TheirEntityRepository arg) {</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> this.repository = arg;</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> }</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> public int doSomething(int id) {</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> return repository.selectById(id).getSomething();</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> }</span><br /><span style="font-family: courier new, monospace; font-size: 100%;">}</span></div> <br /> <br /> You can do this even if you don't have access to source code for <span style="font-family: Courier New, monospace;">TheirEntity</span>, since you're not changing the source itself, but merely encapsulating its static methods in an injectable interface. The techniques shown here generalize to the case where a static method acts as a Factory of objects.<br /> <br /> Now you can inject different implementations of the repository for different tests, such as "never finds anything," "always throws an exception," "only returns a <span style="font-family: Courier New, monospace;">TheirEntity</span> if the id is a prime," and so forth. These kinds of tests would've been impossible before this refactoring.<br /> <br /> Remember to download <a href="http://code.google.com/testing/TotT-2008-06-26.pdf">this episode</a> of Testing on the Toilet and post it in your office. <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> You're pair programming and, as many brilliant people are apt to do, talking out loud. "I'll make a mock, inject it, and rerun the test. It should pa- ...D'OH" Your partner notices the exception <i>"ConnectionFactory not initialized"</i>. "What?" she says, "Something is using the database? Dang, and this was supposed to be a small test."<br /> <br /> Upon inspection you find that your class is calling a <b><span style="color: maroon;">static</span></b> method on some other class. You've got <b><span style="color: maroon;">Static Cling</span></b>! If you're (ab)using a data persistence layer that generates code which relies on static methods, <i>and weren't careful</i>, your code might look something like this:<br /> <br /> <div style="background: #e6f5ff none repeat scroll 0% 50%; border: 1px solid #808080; margin-bottom: 0pt; margin-left: 0.39in; margin-right: 0.39in; padding: 0.1in;"> <span style="font-family: courier new, monospace; font-size: 100%;">public class MyObject {</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> public int doSomething(int id) {</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> return TheirEntity.selectById(id).getSomething();</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> }</span><br /><span style="font-family: courier new, monospace; font-size: 100%;">}</span></div> <br /> <br /> As a result, you can't call doSomething without calling <span style="font-family: Courier New, monospace;">TheirEntity</span>'s static method. This code is hard to test because static methods are <b><span style="color: maroon;">impossible</span></b> to mock in Java.<br /> <br /> So, how do you get rid of this form of Static Cling and get that small test to pass? You can use a technique sometimes known as the <b><span style="color: maroon;">Repository Pattern</span></b>, a form of Abstract Factory. Create an interface and an implementation with the unmockable static method calls:<br /> <br /> <div style="background: #e6f5ff none repeat scroll 0% 50%; border: 1px solid #808080; margin-bottom: 0pt; margin-left: 0.39in; margin-right: 0.39in; padding: 0.1in;"> <span style="font-family: courier new, monospace; font-size: 100%;">interface TheirEntityRepository {</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> TheirEntity selectById(int id);</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> // other static methods on TheirEntity can be</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> // represented here too</span><br /><span style="font-family: courier new, monospace; font-size: 100%;">}</span><br /><span style="font-family: courier new, monospace; font-size: 100%;">public class TheirEntityStaticRepository</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> implements TheirEntityRepository {</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> public TheirEntity selectById(int id) { // non-static</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> return TheirEntity.selectById(id); // calls static method</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> }</span><br /><span style="font-family: courier new, monospace; font-size: 100%;">}</span></div> <br /> <br /> Next, inject a <span style="font-family: Courier New, monospace;">TheirEntityRepository</span> into <span style="font-family: Courier New, monospace;">MyObject</span> and use it instead of calls to the static method:<br /> <br /> <div style="background: #e6f5ff none repeat scroll 0% 50%; border: 1px solid #808080; margin-bottom: 0pt; margin-left: 0.39in; margin-right: 0.39in; padding: 0.1in;"> <span style="font-family: courier new, monospace; font-size: 100%;">public class MyObject {</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> private final TheirEntityRepository repository;</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> public MyEntity(TheirEntityRepository arg) {</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> this.repository = arg;</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> }</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> public int doSomething(int id) {</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> return repository.selectById(id).getSomething();</span><br /><span style="font-family: courier new, monospace; font-size: 100%;"> }</span><br /><span style="font-family: courier new, monospace; font-size: 100%;">}</span></div> <br /> <br /> You can do this even if you don't have access to source code for <span style="font-family: Courier New, monospace;">TheirEntity</span>, since you're not changing the source itself, but merely encapsulating its static methods in an injectable interface. The techniques shown here generalize to the case where a static method acts as a Factory of objects.<br /> <br /> Now you can inject different implementations of the repository for different tests, such as "never finds anything," "always throws an exception," "only returns a <span style="font-family: Courier New, monospace;">TheirEntity</span> if the id is a prime," and so forth. These kinds of tests would've been impossible before this refactoring.<br /> <br /> Remember to download <a href="http://code.google.com/testing/TotT-2008-06-26.pdf">this episode</a> of Testing on the Toilet and post it in your office. <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Google Testing Blog:TotT: Defeat "Static Cling"&url=https://testing.googleblog.com/2008/06/defeat-static-cling.html&via=googletesting'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://testing.googleblog.com/2008/06/defeat-static-cling.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='comment-container'> <i class='comment-img material-icons'>  </i> <a href='https://testing.googleblog.com/2008/06/defeat-static-cling.html#comments' style='font-weight: 500; text-decoration: underline;'>4 comments</a> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://testing.googleblog.com/2008/06/defeat-static-cling.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> <span class='labels-caption'> Labels: </span> <span class='labels'> <a class='label' href='https://testing.googleblog.com/search/label/TotT' rel='tag'> TotT </a> </span> </div> </div> </div> <div class='post' data-id='1564984214103146003' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://testing.googleblog.com/2008/06/test-engineering-class-project-at-uc.html' itemprop='url' title='Test Engineering Class Project at UC-Irivine'> Test Engineering Class Project at UC-Irivine </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Tuesday, June 24, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <span class="byline-author"></span><span id="egxw" style="font-size:100%;">Posted by George Pirocanac, Test Engineering Manager<br /></span><br />For the past nine months it has been my pleasure to work with a group of undergrad students from UC-Irvine as part of their senior class project. The course was run by professor Hadar Ziv and teaching assistant Sameer Patil. It focused on providing students industry experience by working with customers (in this case us) to formulate product requirements and deliver working software. Jason Robbins from the Google Irvine office was the lead for another project and several other local companies also participated.<br /><br />Our team members included Michelle Alvaraz, Jason Dramby, Peter Lee and Gabriela Marcu. It was the only project dealing directly with test engineering and one of our goals was specifically to create a plan and framework for testing the Google Mashup Editor (GME) tag language.<br /><br />For those unfamiliar with the GME, it is a framework for developing simple web applications and mashups using a custom set of XML tags, Javascript, CSS and HTML. More information about the GME can be found <a title="GME documentation" target="_blank" href="http://code.google.com/gme/" id="mh2.">here</a>.<br /><br />The first three months of the class were spent learning about the the GME and performing exploratory testing. The team became very familiar with the editor and created several mashups (You can try one of them <a title="sample mashup" target="_blank" href="http://digikitchen2.googlemashups.com/" id="ytlv">here.</a>). They also created a traditional test plan which focused on testing the tag language. Later they executed this test plan by compiling and running their sample mashups on a variety of browsers.<br /><br />After a couple of iterations of this test plan they quickly encountered some of the typical challenges associated with the traditional approach - namely human resource oversubscription in test execution and insufficient coverage.<br /><br />We addressed with the first issue through automation and the team learned to automate their manual tests of the mashups with <a title="Selenium" target="_blank" href="http://www.openqa.org/selenium/" id="e9ra">Selenium</a>. They first used Selenium IDE to learn the basic Selenium commands and concepts such as locators. Afterwards they used the "Export Test As..." feature in IDE to create Python tests that would be run under a local server with Selenium-RC. The latter got them to a point where they could execute the existing test plan<br />automatically on three different platforms (Windows, Linux, MacOS).<br /><br />Expanding coverage was less straightforward. The traditional approach would be to use the existing resources to write more tests. We, however, decided to create a framework that would itself generate more tests. This dovetailed nicely with the classroom material which was product-centric and focused on gathering customer requirements, creating a design document and delivering the software. In our case, the group's product was to be a <i id="da2_">GME Test Suite Creator</i>.<br /><br />As a starting point we looked at the following simple Python script which creates a simple cross product on lists of strings:<span id="x3ry" style="font-family: Courier New;"><br /><br />#!/usr/bin/python</span><span id="x3ry0" style="font-family: Courier New;"><br /><br />def cross(args):</span><span id="x3ry1" style="font-family: Courier New;"><br /> ans = [[]]</span><span id="x3ry2" style="font-family: Courier New;"><br /> for arg in args:</span><span id="x3ry3" style="font-family: Courier New;"><br /> ans = [x+[y] for x in ans for y in arg]</span><span id="x3ry4" style="font-family: Courier New;"><br /> return ans</span><br /><br /><span id="x3ry5" style="font-family: Courier New;">def pprint(lists):</span><span id="x3ry6" style="font-family: Courier New;"><br /> for list in lists:</span><span id="x3ry7" style="font-family: Courier New;"><br /> a = ''</span><span id="x3ry8" style="font-family: Courier New;"><br /> for s in list:</span><span id="x3ry9" style="font-family: Courier New;"><br /> a = a + s</span><span id="x3ry10" style="font-family: Courier New;"><br /> print a</span><span id="x3ry12" style="font-family: Courier New;"><br /><br />tags = [ ['<'],</span><span id="x3ry14" style="font-family: Courier New;"><br /> ['gm:page '],</span><span id="x3ry16" style="font-family: Courier New;"><br /> ['', 'authenticate=true', 'authenticate=false',<br /> 'authenticate=invalid'],</span><span id="x3ry18" style="font-family: Courier New;"><br /> ['/>'] ]</span><span id="x3ry21" style="font-family: Courier New;"><br /> <br />lists = cross(tags)</span><span id="x3ry23" style="font-family: Courier New;"><br />pprint(lists)</span><br /><br />Running the script yields the following combination of tags:<span id="gqx9" style="font-family: Courier New;"><br /></span><br />< <span id="gqx9" style="font-family: Courier New;">gm:page /</span>><span id="gqx90" style="font-family: Courier New;"><br /></span>< <span id="gqx9" style="font-family: Courier New;"></span><span id="gqx90" style="font-family: Courier New;">gm:page authenticate=true</span><span id="gqx9" style="font-family: Courier New;">/</span>><span id="gqx90" style="font-family: Courier New;"></span><span id="gqx91" style="font-family: Courier New;"><br /></span>< <span id="gqx9" style="font-family: Courier New;"></span><span id="gqx91" style="font-family: Courier New;">gm:page authenticate=false</span><span id="gqx9" style="font-family: Courier New;">/</span>><span id="gqx90" style="font-family: Courier New;"></span><span id="gqx92" style="font-family: Courier New;"><br /></span>< <span id="gqx92" style="font-family: Courier New;">gm:page authenticate=invalid</span><span id="gqx9" style="font-family: Courier New;">/</span>><span id="gqx90" style="font-family: Courier New;"><br /></span><br /><br />Each one could be used in a mashup that used the page tag. Likewise, the other tags from the GME tag language could be expanded with various combinations of valid and invalid attributes. These tag combinations could then be individually inserted into <i id="sz8:">skeleton</i> mashups producing a large number of both positive and negative tests which would be performed under Selenium-RC.<br /><br />This was the basic idea of the <i id="bebb">GME Test Suite Creator</i> and the team implemented a GUI to facilitate the three steps in creating and running a testsuite:<br /><br /><div id="bulp0" style="margin-left: 40px;"><ul id="fg1-"><li id="fg1-0">Code Generation - The selection of tags and creation of tests.</li></ul></div><div id="fg1-1" style="margin-left: 40px;"><ul id="fg1-2"><li id="fg1-3">Code Preview - The examination and execution of created tests</li></ul></div><div id="fg1-4" style="margin-left: 40px;"><ul id="fg1-5"><li id="fg1-6">Test Reporting - The examination of test results.</li></ul></div><br />The figure below shows the Code Generation tab of the <i id="vto8">GME Test Suite Creator.</i> It displays a hierarchical view of the tabs and allows the user to select which tags to include in the sample tests. The sample test is generated from a <i id="yr4r">skeleton </i>test modeled after the documentation example scraped from the code.google.com website. This was a nice idea which added testing of the documentation to the process.<br /><br /><div id="p_9m" style="padding: 1em 0pt; text-align: left;"><img id="w.qq" src="https://docs.google.com/a/google.com/File?id=chbtmb2v_60hrsvk3gc_b" style="width: 613px; height: 465px;" /></div>An interesting problem that these types of automatic test generation frameworks can encounter is the combinatorial explosion of generated tests. For example, if each tag attribute can have 8 possible values and a sample mashup contains 10 tags, enumerating each combination would take roughly 1 billion (8<sup id="aip2">10</sup> = 2<sup id="aip20">30</sup>) tests! To address this, the team created an Options dialog box that would allow the user to specify different test suite sizes in addition to the test suite name and type. A further refinement, allowing the user to select which set of specific values to use for tag attributes would have been implemented if the team had more time.<br /><div id="i8gb" style="padding: 1em 0pt; text-align: left;"><img id="mip9" src="https://docs.google.com/a/google.com/File?id=chbtmb2v_64wtg679fs_b" style="width: 192px; height: 264px;" /></div><br />The next figure shows the Code Preview tab of the <i id="kck1">GME Test Suite Creator. </i>It shows the list of tests created under a given test suite and allows the user to manage and execute the test suite.<br /><div id="errr" style="padding: 1em 0pt; text-align: left;"><img id="tr1h" src="https://docs.google.com/a/google.com/File?id=chbtmb2v_65fswffchr_b" style="width: 574px; height: 439px;" /></div><br />Finally, the Test Report Tab shows the results of the tests executed under Selenium-RC.<br /><br /><div id="taso" style="padding: 1em 0pt; text-align: left;"><img id="hupi" src="https://docs.google.com/a/google.com/File?id=chbtmb2v_62czwfhgc2_b" style="width: 611px; height: 469px;" /></div><i id="zwf_">GME Test Suite Creator </i>was itself written in Python and hosted on Windows, Linux and MacOS.<br />The team presented and demonstrated the <i id="zwf_0">GME Test Suite Creator</i> to faculty and other student/industry teams as part of the UC-Irvine ICS Student Show Case. Over the next few weeks I will be kicking the tires and evaluating the battle worthiness of the <i id="z.p1">GME Test Suite Creator</i> delivery which included source code and a complete set of documentation.<br /><br />I certainly had a wonderful time interacting with the team and participating in this program!<br /><br /><div id="ubqj" style="padding: 1em 0pt; text-align: left;"><img id="x:l6" src="https://docs.google.com/a/google.com/File?id=chbtmb2v_63crvhfvcq_b" style="width: 432px; height: 290px;" /></div>The GME Test Suite Creator Team (from left to right: Gabriela Marcu, Peter Lee, <br />Michelle Alvarez, Jason Dramby and George Pirocanac) <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <span class="byline-author"></span><span id="egxw" style="font-size:100%;">Posted by George Pirocanac, Test Engineering Manager<br /></span><br />For the past nine months it has been my pleasure to work with a group of undergrad students from UC-Irvine as part of their senior class project. The course was run by professor Hadar Ziv and teaching assistant Sameer Patil. It focused on providing students industry experience by working with customers (in this case us) to formulate product requirements and deliver working software. Jason Robbins from the Google Irvine office was the lead for another project and several other local companies also participated.<br /><br />Our team members included Michelle Alvaraz, Jason Dramby, Peter Lee and Gabriela Marcu. It was the only project dealing directly with test engineering and one of our goals was specifically to create a plan and framework for testing the Google Mashup Editor (GME) tag language.<br /><br />For those unfamiliar with the GME, it is a framework for developing simple web applications and mashups using a custom set of XML tags, Javascript, CSS and HTML. More information about the GME can be found <a title="GME documentation" target="_blank" href="http://code.google.com/gme/" id="mh2.">here</a>.<br /><br />The first three months of the class were spent learning about the the GME and performing exploratory testing. The team became very familiar with the editor and created several mashups (You can try one of them <a title="sample mashup" target="_blank" href="http://digikitchen2.googlemashups.com/" id="ytlv">here.</a>). They also created a traditional test plan which focused on testing the tag language. Later they executed this test plan by compiling and running their sample mashups on a variety of browsers.<br /><br />After a couple of iterations of this test plan they quickly encountered some of the typical challenges associated with the traditional approach - namely human resource oversubscription in test execution and insufficient coverage.<br /><br />We addressed with the first issue through automation and the team learned to automate their manual tests of the mashups with <a title="Selenium" target="_blank" href="http://www.openqa.org/selenium/" id="e9ra">Selenium</a>. They first used Selenium IDE to learn the basic Selenium commands and concepts such as locators. Afterwards they used the "Export Test As..." feature in IDE to create Python tests that would be run under a local server with Selenium-RC. The latter got them to a point where they could execute the existing test plan<br />automatically on three different platforms (Windows, Linux, MacOS).<br /><br />Expanding coverage was less straightforward. The traditional approach would be to use the existing resources to write more tests. We, however, decided to create a framework that would itself generate more tests. This dovetailed nicely with the classroom material which was product-centric and focused on gathering customer requirements, creating a design document and delivering the software. In our case, the group's product was to be a <i id="da2_">GME Test Suite Creator</i>.<br /><br />As a starting point we looked at the following simple Python script which creates a simple cross product on lists of strings:<span id="x3ry" style="font-family: Courier New;"><br /><br />#!/usr/bin/python</span><span id="x3ry0" style="font-family: Courier New;"><br /><br />def cross(args):</span><span id="x3ry1" style="font-family: Courier New;"><br /> ans = [[]]</span><span id="x3ry2" style="font-family: Courier New;"><br /> for arg in args:</span><span id="x3ry3" style="font-family: Courier New;"><br /> ans = [x+[y] for x in ans for y in arg]</span><span id="x3ry4" style="font-family: Courier New;"><br /> return ans</span><br /><br /><span id="x3ry5" style="font-family: Courier New;">def pprint(lists):</span><span id="x3ry6" style="font-family: Courier New;"><br /> for list in lists:</span><span id="x3ry7" style="font-family: Courier New;"><br /> a = ''</span><span id="x3ry8" style="font-family: Courier New;"><br /> for s in list:</span><span id="x3ry9" style="font-family: Courier New;"><br /> a = a + s</span><span id="x3ry10" style="font-family: Courier New;"><br /> print a</span><span id="x3ry12" style="font-family: Courier New;"><br /><br />tags = [ ['<'],</span><span id="x3ry14" style="font-family: Courier New;"><br /> ['gm:page '],</span><span id="x3ry16" style="font-family: Courier New;"><br /> ['', 'authenticate=true', 'authenticate=false',<br /> 'authenticate=invalid'],</span><span id="x3ry18" style="font-family: Courier New;"><br /> ['/>'] ]</span><span id="x3ry21" style="font-family: Courier New;"><br /> <br />lists = cross(tags)</span><span id="x3ry23" style="font-family: Courier New;"><br />pprint(lists)</span><br /><br />Running the script yields the following combination of tags:<span id="gqx9" style="font-family: Courier New;"><br /></span><br />< <span id="gqx9" style="font-family: Courier New;">gm:page /</span>><span id="gqx90" style="font-family: Courier New;"><br /></span>< <span id="gqx9" style="font-family: Courier New;"></span><span id="gqx90" style="font-family: Courier New;">gm:page authenticate=true</span><span id="gqx9" style="font-family: Courier New;">/</span>><span id="gqx90" style="font-family: Courier New;"></span><span id="gqx91" style="font-family: Courier New;"><br /></span>< <span id="gqx9" style="font-family: Courier New;"></span><span id="gqx91" style="font-family: Courier New;">gm:page authenticate=false</span><span id="gqx9" style="font-family: Courier New;">/</span>><span id="gqx90" style="font-family: Courier New;"></span><span id="gqx92" style="font-family: Courier New;"><br /></span>< <span id="gqx92" style="font-family: Courier New;">gm:page authenticate=invalid</span><span id="gqx9" style="font-family: Courier New;">/</span>><span id="gqx90" style="font-family: Courier New;"><br /></span><br /><br />Each one could be used in a mashup that used the page tag. Likewise, the other tags from the GME tag language could be expanded with various combinations of valid and invalid attributes. These tag combinations could then be individually inserted into <i id="sz8:">skeleton</i> mashups producing a large number of both positive and negative tests which would be performed under Selenium-RC.<br /><br />This was the basic idea of the <i id="bebb">GME Test Suite Creator</i> and the team implemented a GUI to facilitate the three steps in creating and running a testsuite:<br /><br /><div id="bulp0" style="margin-left: 40px;"><ul id="fg1-"><li id="fg1-0">Code Generation - The selection of tags and creation of tests.</li></ul></div><div id="fg1-1" style="margin-left: 40px;"><ul id="fg1-2"><li id="fg1-3">Code Preview - The examination and execution of created tests</li></ul></div><div id="fg1-4" style="margin-left: 40px;"><ul id="fg1-5"><li id="fg1-6">Test Reporting - The examination of test results.</li></ul></div><br />The figure below shows the Code Generation tab of the <i id="vto8">GME Test Suite Creator.</i> It displays a hierarchical view of the tabs and allows the user to select which tags to include in the sample tests. The sample test is generated from a <i id="yr4r">skeleton </i>test modeled after the documentation example scraped from the code.google.com website. This was a nice idea which added testing of the documentation to the process.<br /><br /><div id="p_9m" style="padding: 1em 0pt; text-align: left;"><img id="w.qq" src="https://docs.google.com/a/google.com/File?id=chbtmb2v_60hrsvk3gc_b" style="width: 613px; height: 465px;" /></div>An interesting problem that these types of automatic test generation frameworks can encounter is the combinatorial explosion of generated tests. For example, if each tag attribute can have 8 possible values and a sample mashup contains 10 tags, enumerating each combination would take roughly 1 billion (8<sup id="aip2">10</sup> = 2<sup id="aip20">30</sup>) tests! To address this, the team created an Options dialog box that would allow the user to specify different test suite sizes in addition to the test suite name and type. A further refinement, allowing the user to select which set of specific values to use for tag attributes would have been implemented if the team had more time.<br /><div id="i8gb" style="padding: 1em 0pt; text-align: left;"><img id="mip9" src="https://docs.google.com/a/google.com/File?id=chbtmb2v_64wtg679fs_b" style="width: 192px; height: 264px;" /></div><br />The next figure shows the Code Preview tab of the <i id="kck1">GME Test Suite Creator. </i>It shows the list of tests created under a given test suite and allows the user to manage and execute the test suite.<br /><div id="errr" style="padding: 1em 0pt; text-align: left;"><img id="tr1h" src="https://docs.google.com/a/google.com/File?id=chbtmb2v_65fswffchr_b" style="width: 574px; height: 439px;" /></div><br />Finally, the Test Report Tab shows the results of the tests executed under Selenium-RC.<br /><br /><div id="taso" style="padding: 1em 0pt; text-align: left;"><img id="hupi" src="https://docs.google.com/a/google.com/File?id=chbtmb2v_62czwfhgc2_b" style="width: 611px; height: 469px;" /></div><i id="zwf_">GME Test Suite Creator </i>was itself written in Python and hosted on Windows, Linux and MacOS.<br />The team presented and demonstrated the <i id="zwf_0">GME Test Suite Creator</i> to faculty and other student/industry teams as part of the UC-Irvine ICS Student Show Case. Over the next few weeks I will be kicking the tires and evaluating the battle worthiness of the <i id="z.p1">GME Test Suite Creator</i> delivery which included source code and a complete set of documentation.<br /><br />I certainly had a wonderful time interacting with the team and participating in this program!<br /><br /><div id="ubqj" style="padding: 1em 0pt; text-align: left;"><img id="x:l6" src="https://docs.google.com/a/google.com/File?id=chbtmb2v_63crvhfvcq_b" style="width: 432px; height: 290px;" /></div>The GME Test Suite Creator Team (from left to right: Gabriela Marcu, Peter Lee, <br />Michelle Alvarez, Jason Dramby and George Pirocanac) <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Google Testing Blog:Test Engineering Class Project at UC-Irivine&url=https://testing.googleblog.com/2008/06/test-engineering-class-project-at-uc.html&via=googletesting'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://testing.googleblog.com/2008/06/test-engineering-class-project-at-uc.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='comment-container'> <i class='comment-img material-icons'>  </i> <a href='https://testing.googleblog.com/2008/06/test-engineering-class-project-at-uc.html#comments' style='font-weight: 500; text-decoration: underline;'>3 comments</a> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://testing.googleblog.com/2008/06/test-engineering-class-project-at-uc.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> <span class='labels-caption'> Labels: </span> <span class='labels'> <a class='label' href='https://testing.googleblog.com/search/label/George%20Pirocanac' rel='tag'> George Pirocanac </a> </span> </div> </div> </div> <div class='post' data-id='660789245724190864' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://testing.googleblog.com/2008/06/productivity-games-using-games-to.html' itemprop='url' title='Productivity Games – Using Games to Improve Quality'> Productivity Games – Using Games to Improve Quality </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Saturday, June 21, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> Editor's note (Pat Copeland, Engineering Productivity Director, Google): On occasion we ask a special guest to post on an interesting topic. Ross has some really interesting ideas about how to use games to influence behavior. I'm a big fan. Enjoy!<br /><br /><br />Ross Smith, Director of Test, Microsoft Windows Core Security<br /><i><br />“Quality takes you out of yourself, makes you aware of the world around you.” [1]<br /></i><br /><br /><p class="MsoNormal">The “Gamer Generation” is here. <span style="font-size:0;"></span>According to the <a href="http://www.washingtonpost.com/wp-dyn/content/article/2006/05/07/AR2006050700172.html">Washington Post</a>, in 2006 at least 40% of Americans play video games on a computer or a console. The largest demographic is 18-34 year-<span class="blsp-spelling-error" id="SPELLING_ERROR_0">olds</span>, many of whom are working as our friends and peers as software developers and testers. <span style="font-size:0;"></span>There is a great book, <a href="http://books.google.com/books?id=uxz6UU_AW3cC">Got Game</a>, which describes the impact of games on the workforce of today and in the future.</p><p class="MsoNormal">Many businesses are wondering these days how to use simple concepts popular in video games and apply them to work.</p><p class="MsoNormal">It’s happening already. From a construction site with a sign posted with “days since last accident” to the car dealer with <span class="blsp-spelling-error" id="SPELLING_ERROR_1">salespersons</span> leader board scrawled out in chalk. Simple competition helps work get done in all kinds of industries. The success of sales contests is a great example of how well competition works.</p><p class="MsoNormal"><i>“In every job that must be done, there is an element of fun. You find the fun and—SNAP—the job’s a game!” —Mary Poppins</i></p><p class="MsoNormal">A company called <a href="http://www.seriosity.com/products.html"><span class="blsp-spelling-error" id="SPELLING_ERROR_2">Seriosity</span></a> has made interesting use of video game concepts at work with their application of virtual currency to email. To help with information overload from an overflowing inbox, email senders can “spend” virtual currency (<span class="blsp-spelling-error" id="SPELLING_ERROR_3">Serios</span>) to help prioritize their messages. Spending to denote the importance of a message is not a whole lot different than buying new golf clubs with virtual money earned in a Tiger Woods game, buying new tires in a car racing game – or using gamer points to upgrade your armor in an <span class="blsp-spelling-error" id="SPELLING_ERROR_4">RPG</span> (Role-playing Game). Wired Magazine had a <a href="http://www.wired.com/wired/archive/14.04/learn.html">great article</a> on the use of WOW as a leadership training game. Playing games at work is more than just a quick game of online Hearts with one finger on the “<a href="http://en.wikipedia.org/wiki/Boss_key">boss key</a>”. Games at work can have real impact.</p><p class="MsoNormal">With other industries using productivity games, what about software development?<span style="font-size:0;"> </span>How can productivity games help testers improve the quality of the products they test?<span style="font-size:0;"> </span>One of the more famous test techniques is the bug bash. Teams pick a certain date, and everyone bangs on a certain area of the product to find bugs. At the end, prizes are awarded while everyone enjoys pizza and drinks. That sounds a lot like game, doesn't it?<span style="font-size:0;"> </span>It’s also a perfect example of a simple productivity game.</p><p class="MsoNormal">As the world of software gets more complex and the test matrix grows, there is no shortage of opportunities for testers to do more testing. Quality is always “improved”, it’s never completed, fixed or finished. Therefore, testers must choose from a variety of techniques and activities to pursue tasks with the highest return and value. In 1990, <a href="http://nobelprize.org/nobel_prizes/economics/laureates/1990/index.html">Harry <span class="blsp-spelling-error" id="SPELLING_ERROR_5">Markowitz</span></a> won the Nobel Prize for his work on <a href="http://cowles.econ.yale.edu/P/cm/m16/m16-all.pdf">Portfolio Selection</a> (that he began in the 1950’s). The theory, familiar in financial markets and mutual funds, is that a portfolio of diverse assets with varying risk and returns actually reduces risk in time uncertain conditions. Testers can benefit from the work on portfolio selection by varying the techniques they use to find defects. However, some techniques are more expensive, more difficult, or less attractive than others. Some teams, in some situations, can rely on the altruism and volunteer efforts – <a href="http://en.wikipedia.org/wiki/Organizational_citizenship_behavior">organizational citizenship behaviors</a> – of their members to take on the more difficult tasks. However, that doesn't always work, and other incentives may be required. That’s where productivity games can help.</p><p class="MsoNormal">When a project needs a bit of a push towards a certain behavior, building a game around it can help.<span style="font-size:0;"> </span>For example, if a test team wants to improve the usage of unit tests by developers, encourage the team to “<a href="http://en.wikipedia.org/wiki/Eating_one">eat their own <span class="blsp-spelling-error" id="SPELLING_ERROR_6">dogfood</span></a>” or run automated tests on personal machines overnight, then creating a game will help people’s motivation can motivate people to participate in those activities. </p><p class="MsoNormal">Productivity games differ from traditional games in a few distinct ways. The goal of a productivity game is to attract players. <b>These games don’t need winners as much as they need players. </b>In many cases, productivity games don’t even need prizes. Productivity games can be simple. There’s no need to invest in expensive graphics or 3-D modeling – people play the game to compete around a work activity, not because of the appeal of the user interface. A simple leader board might be all that’s needed. </p><p class="MsoNormal">Using games at work is a powerful and effective method to influence change in organizational behavior, and therefore requires care in the design and use. It is possible to overdo the use of games to a point where they are counter-productive or ineffective. Successful game design is best achieved through experience and experimentation, and the goal should be to keep things interesting enough to always attract players. A game where one player leaps out to an insurmountable lead is not effective, because that will discourage others from playing. When a team wants to encourage testers to invest in fault injection techniques, setting up a leader board with bug totals found via fault injection techniques will attract attention of other testers, often just by word-of-mouth. You should encourage team-wide competition, smack talk, and public embarrassment as a means to draw attention. Games should be short in duration.<span style="font-size:0;"> </span>Many testers remember the Dilbert “I’m gonna write me a new minivan” from 11/13/95. This is what results from a poorly designed productivity game.</p><p class="MsoNormal">Productivity games are great at motivating people to do things and change behavior. And as Uncle Ben said to <span class="blsp-spelling-error" id="SPELLING_ERROR_7">Spiderman</span>, “With great power comes great responsibility”. It’s critical to have specific goals for the games, and to understand the impact before deploying a game – it’s pretty likely that people will play, at least initially, and the impact may not be what you intended. Keep the duration of games short in order to be able to adjust. And finally, keep the games focused on volunteer or “extra” activities. A game designed around an individual’s job or portions of everyone’s regular job can introduce unusual feelings when it comes to rewards and performance evaluation. It’s easier to steer clear of that than to try to figure out the right balance.</p><p class="MsoNormal"><span class="blsp-spelling-error" id="SPELLING_ERROR_8">Shigeru</span> <span class="blsp-spelling-error" id="SPELLING_ERROR_9">Miyamoto</span>, who designed Super Mario Bros., talks about games as “miniature gardens”, metaphorically representing the cultural values, humanity, and challenges of everyday life the way a miniature garden might represent a real one. </p><p class="MsoNormal"><i>The whole idea, for me, is about the exploration of a <span class="blsp-spelling-error" id="SPELLING_ERROR_10">hakoniwa</span>, a miniature garden. It's like a garden in a box, where if you look at it from different angles, you can see different plants and arrangements. And you have that sense of surprise and exploration. There's always things you can find. </i>[2]<br /></p><p class="MsoNormal">Games are a lot like testing.<span style="font-size:0;"> </span>Software quality assurance and testing efforts represent a proxy for real users in much the same way that games are a proxy for the real world. The challenges that Mario faces with fire-breathing dragons and knife throwing turtles are balanced by the allure of coins and princesses.<span style="font-size:0;"> </span>A testing organization has a good idea of the tools available in their portfolio to improve quality and eliminate those “fire-breathing dragons” for their customers. Productivity games allow teams to offer coins and position rewards around their equivalents of <span class="blsp-spelling-error" id="SPELLING_ERROR_11">Markowitz</span>’s “diverse assets” at their disposal, in the form of defect detection and removal techniques, to improve quality. </p><p class="MsoNormal"><span style="font-size:0;"></span>For the players, productivity games offer people the ability to learn, solve problems, and earn a reward. They offer a way to challenge players to compete, to explore and discover, and to establish a surrogate identity or status via a leader board. There are many fundamental motivations to play a game. “<i>If you build it, they will come [3]." </i>A good productivity game designer can build a game around “work that needs to be done that no one wants to do” – and like the lone teenager who plays Halo for weeks on end, people will take on that work. Experiment and explore – the results can be surprising.</p><p class="MsoNormal">I’d be interested in any <a href="mailto:rosss@defectprevention.org?subject=Comments%20on%20Productivity%20Games">comments about Productivity Games</a> that you might have.</p><p class="MsoNormal" style="MARGIN-BOTTOM: 0pt">Thanks,</p><p class="MsoNormal" style="MARGIN-BOTTOM: 0pt">Ross Smith</p><p class="MsoNormal" style="MARGIN-BOTTOM: 0pt"><a href="http://www.defectprevention.org/">http://www.defectprevention.org/</a> </p><p class="MsoNormal"><b><!--xml:namespace prefix = o /--><o:p></o:p></b></p><p class="MsoNormal"><o:p></o:p></p><p class="MsoNormal"><b>Interesting Links: <span style="TEXT-DECORATION: underline"></span></b></p><p><a href="http://news.bbc.co.uk/2/hi/technology/7030234.stm" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>When Work becomes a Game</u></span></a></p><p><a href="http://seriousgames.org/index2.html" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>Serious Games Initiative</u></span></a></p><p><a href="http://www.e-learningguru.com/books/gotgame.pdf" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>Got Game - How the Gamer Generation is Reshaping Business Forever</u></span></a><span style="font-family:Calibri;font-size:100%;"> </span></p><p><a href="http://www.defectprevention.org/book.aspx" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>Chapter 5 – Productivity Games - The Practical Guide to Defect Prevention</u></span></a></p><p><a href="http://www.defectprevention.org/downloads/bug+hunter.pdf" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>2008 Serious Games Summit presentation</u></span></a></p><p><a href="http://www.gamasutra.com/education/theses/20030901/gingold_01.shtml" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>Miniature Gardens and Magic Crayons: Games, Spaces, & Worlds</u></span></a></p><p><a href="http://harvardbusinessonline.hbsp.harvard.edu/hbsp/hbr/articles/article.jsp?ml_subscriber=true&ml_action=get-article&&articleID=R0805C&pageNumber=1" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>HBR Leadership’s Online Labs</u></span></a></p><p><a href="http://www.npr.org/templates/story/story.php?storyId=91573868" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>NPR: Software lets users assign value to email</u></span></a></p><p><a href="http://www.edery.org/" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>Game Tycoon blog</u></span></a><span style="font-family:Calibri;font-size:100%;"> (How Video Games are transforming the Business World) </span></p><p><a href="http://productivitygames.blogspot.com/" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>Productivity Games Blog</u></span></a></p><a href="http://www.levityeffect.com/" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>The Levity Effect</u></span></a><br /><br /><p class="MsoNormal"><b><span style="TEXT-DECORATION: underline"></span></b><span style="LINE-HEIGHT: 115%;font-size:85%;" ></span></p><p class="MsoNormal"><span style="LINE-HEIGHT: 115%;font-size:85%;" >Special thanks to Joshua Williams for his help with this post.<o:p></o:p></span><br /></p><hr align="left" width="33%" style="font-size:78;"><br /><div id="edn1"><p class="MsoEndnoteText">[1] Robert <span class="blsp-spelling-error" id="SPELLING_ERROR_13">Pirsig</span>, Zen and the Art of Motorcycle Maintenance<br />[2] Wired Magazine Interview <a title="" href="//www.blogger.com/post-create.g?blogID=15045980#_ednref3" name="_edn3">http://blog.wired.com/games/2007/12/interview-super.html<br /></a>[3] Field of Dreams, 1989</p></div><div id="edn2"></div><div id="edn3"></div> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> Editor's note (Pat Copeland, Engineering Productivity Director, Google): On occasion we ask a special guest to post on an interesting topic. Ross has some really interesting ideas about how to use games to influence behavior. I'm a big fan. Enjoy!<br /><br /><br />Ross Smith, Director of Test, Microsoft Windows Core Security<br /><i><br />“Quality takes you out of yourself, makes you aware of the world around you.” [1]<br /></i><br /><br /><p class="MsoNormal">The “Gamer Generation” is here. <span style="font-size:0;"></span>According to the <a href="http://www.washingtonpost.com/wp-dyn/content/article/2006/05/07/AR2006050700172.html">Washington Post</a>, in 2006 at least 40% of Americans play video games on a computer or a console. The largest demographic is 18-34 year-<span class="blsp-spelling-error" id="SPELLING_ERROR_0">olds</span>, many of whom are working as our friends and peers as software developers and testers. <span style="font-size:0;"></span>There is a great book, <a href="http://books.google.com/books?id=uxz6UU_AW3cC">Got Game</a>, which describes the impact of games on the workforce of today and in the future.</p><p class="MsoNormal">Many businesses are wondering these days how to use simple concepts popular in video games and apply them to work.</p><p class="MsoNormal">It’s happening already. From a construction site with a sign posted with “days since last accident” to the car dealer with <span class="blsp-spelling-error" id="SPELLING_ERROR_1">salespersons</span> leader board scrawled out in chalk. Simple competition helps work get done in all kinds of industries. The success of sales contests is a great example of how well competition works.</p><p class="MsoNormal"><i>“In every job that must be done, there is an element of fun. You find the fun and—SNAP—the job’s a game!” —Mary Poppins</i></p><p class="MsoNormal">A company called <a href="http://www.seriosity.com/products.html"><span class="blsp-spelling-error" id="SPELLING_ERROR_2">Seriosity</span></a> has made interesting use of video game concepts at work with their application of virtual currency to email. To help with information overload from an overflowing inbox, email senders can “spend” virtual currency (<span class="blsp-spelling-error" id="SPELLING_ERROR_3">Serios</span>) to help prioritize their messages. Spending to denote the importance of a message is not a whole lot different than buying new golf clubs with virtual money earned in a Tiger Woods game, buying new tires in a car racing game – or using gamer points to upgrade your armor in an <span class="blsp-spelling-error" id="SPELLING_ERROR_4">RPG</span> (Role-playing Game). Wired Magazine had a <a href="http://www.wired.com/wired/archive/14.04/learn.html">great article</a> on the use of WOW as a leadership training game. Playing games at work is more than just a quick game of online Hearts with one finger on the “<a href="http://en.wikipedia.org/wiki/Boss_key">boss key</a>”. Games at work can have real impact.</p><p class="MsoNormal">With other industries using productivity games, what about software development?<span style="font-size:0;"> </span>How can productivity games help testers improve the quality of the products they test?<span style="font-size:0;"> </span>One of the more famous test techniques is the bug bash. Teams pick a certain date, and everyone bangs on a certain area of the product to find bugs. At the end, prizes are awarded while everyone enjoys pizza and drinks. That sounds a lot like game, doesn't it?<span style="font-size:0;"> </span>It’s also a perfect example of a simple productivity game.</p><p class="MsoNormal">As the world of software gets more complex and the test matrix grows, there is no shortage of opportunities for testers to do more testing. Quality is always “improved”, it’s never completed, fixed or finished. Therefore, testers must choose from a variety of techniques and activities to pursue tasks with the highest return and value. In 1990, <a href="http://nobelprize.org/nobel_prizes/economics/laureates/1990/index.html">Harry <span class="blsp-spelling-error" id="SPELLING_ERROR_5">Markowitz</span></a> won the Nobel Prize for his work on <a href="http://cowles.econ.yale.edu/P/cm/m16/m16-all.pdf">Portfolio Selection</a> (that he began in the 1950’s). The theory, familiar in financial markets and mutual funds, is that a portfolio of diverse assets with varying risk and returns actually reduces risk in time uncertain conditions. Testers can benefit from the work on portfolio selection by varying the techniques they use to find defects. However, some techniques are more expensive, more difficult, or less attractive than others. Some teams, in some situations, can rely on the altruism and volunteer efforts – <a href="http://en.wikipedia.org/wiki/Organizational_citizenship_behavior">organizational citizenship behaviors</a> – of their members to take on the more difficult tasks. However, that doesn't always work, and other incentives may be required. That’s where productivity games can help.</p><p class="MsoNormal">When a project needs a bit of a push towards a certain behavior, building a game around it can help.<span style="font-size:0;"> </span>For example, if a test team wants to improve the usage of unit tests by developers, encourage the team to “<a href="http://en.wikipedia.org/wiki/Eating_one">eat their own <span class="blsp-spelling-error" id="SPELLING_ERROR_6">dogfood</span></a>” or run automated tests on personal machines overnight, then creating a game will help people’s motivation can motivate people to participate in those activities. </p><p class="MsoNormal">Productivity games differ from traditional games in a few distinct ways. The goal of a productivity game is to attract players. <b>These games don’t need winners as much as they need players. </b>In many cases, productivity games don’t even need prizes. Productivity games can be simple. There’s no need to invest in expensive graphics or 3-D modeling – people play the game to compete around a work activity, not because of the appeal of the user interface. A simple leader board might be all that’s needed. </p><p class="MsoNormal">Using games at work is a powerful and effective method to influence change in organizational behavior, and therefore requires care in the design and use. It is possible to overdo the use of games to a point where they are counter-productive or ineffective. Successful game design is best achieved through experience and experimentation, and the goal should be to keep things interesting enough to always attract players. A game where one player leaps out to an insurmountable lead is not effective, because that will discourage others from playing. When a team wants to encourage testers to invest in fault injection techniques, setting up a leader board with bug totals found via fault injection techniques will attract attention of other testers, often just by word-of-mouth. You should encourage team-wide competition, smack talk, and public embarrassment as a means to draw attention. Games should be short in duration.<span style="font-size:0;"> </span>Many testers remember the Dilbert “I’m gonna write me a new minivan” from 11/13/95. This is what results from a poorly designed productivity game.</p><p class="MsoNormal">Productivity games are great at motivating people to do things and change behavior. And as Uncle Ben said to <span class="blsp-spelling-error" id="SPELLING_ERROR_7">Spiderman</span>, “With great power comes great responsibility”. It’s critical to have specific goals for the games, and to understand the impact before deploying a game – it’s pretty likely that people will play, at least initially, and the impact may not be what you intended. Keep the duration of games short in order to be able to adjust. And finally, keep the games focused on volunteer or “extra” activities. A game designed around an individual’s job or portions of everyone’s regular job can introduce unusual feelings when it comes to rewards and performance evaluation. It’s easier to steer clear of that than to try to figure out the right balance.</p><p class="MsoNormal"><span class="blsp-spelling-error" id="SPELLING_ERROR_8">Shigeru</span> <span class="blsp-spelling-error" id="SPELLING_ERROR_9">Miyamoto</span>, who designed Super Mario Bros., talks about games as “miniature gardens”, metaphorically representing the cultural values, humanity, and challenges of everyday life the way a miniature garden might represent a real one. </p><p class="MsoNormal"><i>The whole idea, for me, is about the exploration of a <span class="blsp-spelling-error" id="SPELLING_ERROR_10">hakoniwa</span>, a miniature garden. It's like a garden in a box, where if you look at it from different angles, you can see different plants and arrangements. And you have that sense of surprise and exploration. There's always things you can find. </i>[2]<br /></p><p class="MsoNormal">Games are a lot like testing.<span style="font-size:0;"> </span>Software quality assurance and testing efforts represent a proxy for real users in much the same way that games are a proxy for the real world. The challenges that Mario faces with fire-breathing dragons and knife throwing turtles are balanced by the allure of coins and princesses.<span style="font-size:0;"> </span>A testing organization has a good idea of the tools available in their portfolio to improve quality and eliminate those “fire-breathing dragons” for their customers. Productivity games allow teams to offer coins and position rewards around their equivalents of <span class="blsp-spelling-error" id="SPELLING_ERROR_11">Markowitz</span>’s “diverse assets” at their disposal, in the form of defect detection and removal techniques, to improve quality. </p><p class="MsoNormal"><span style="font-size:0;"></span>For the players, productivity games offer people the ability to learn, solve problems, and earn a reward. They offer a way to challenge players to compete, to explore and discover, and to establish a surrogate identity or status via a leader board. There are many fundamental motivations to play a game. “<i>If you build it, they will come [3]." </i>A good productivity game designer can build a game around “work that needs to be done that no one wants to do” – and like the lone teenager who plays Halo for weeks on end, people will take on that work. Experiment and explore – the results can be surprising.</p><p class="MsoNormal">I’d be interested in any <a href="mailto:rosss@defectprevention.org?subject=Comments%20on%20Productivity%20Games">comments about Productivity Games</a> that you might have.</p><p class="MsoNormal" style="MARGIN-BOTTOM: 0pt">Thanks,</p><p class="MsoNormal" style="MARGIN-BOTTOM: 0pt">Ross Smith</p><p class="MsoNormal" style="MARGIN-BOTTOM: 0pt"><a href="http://www.defectprevention.org/">http://www.defectprevention.org/</a> </p><p class="MsoNormal"><b><!--xml:namespace prefix = o /--><o:p></o:p></b></p><p class="MsoNormal"><o:p></o:p></p><p class="MsoNormal"><b>Interesting Links: <span style="TEXT-DECORATION: underline"></span></b></p><p><a href="http://news.bbc.co.uk/2/hi/technology/7030234.stm" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>When Work becomes a Game</u></span></a></p><p><a href="http://seriousgames.org/index2.html" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>Serious Games Initiative</u></span></a></p><p><a href="http://www.e-learningguru.com/books/gotgame.pdf" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>Got Game - How the Gamer Generation is Reshaping Business Forever</u></span></a><span style="font-family:Calibri;font-size:100%;"> </span></p><p><a href="http://www.defectprevention.org/book.aspx" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>Chapter 5 – Productivity Games - The Practical Guide to Defect Prevention</u></span></a></p><p><a href="http://www.defectprevention.org/downloads/bug+hunter.pdf" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>2008 Serious Games Summit presentation</u></span></a></p><p><a href="http://www.gamasutra.com/education/theses/20030901/gingold_01.shtml" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>Miniature Gardens and Magic Crayons: Games, Spaces, & Worlds</u></span></a></p><p><a href="http://harvardbusinessonline.hbsp.harvard.edu/hbsp/hbr/articles/article.jsp?ml_subscriber=true&ml_action=get-article&&articleID=R0805C&pageNumber=1" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>HBR Leadership’s Online Labs</u></span></a></p><p><a href="http://www.npr.org/templates/story/story.php?storyId=91573868" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>NPR: Software lets users assign value to email</u></span></a></p><p><a href="http://www.edery.org/" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>Game Tycoon blog</u></span></a><span style="font-family:Calibri;font-size:100%;"> (How Video Games are transforming the Business World) </span></p><p><a href="http://productivitygames.blogspot.com/" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>Productivity Games Blog</u></span></a></p><a href="http://www.levityeffect.com/" target="_blank"><span style="font-family:Calibri;font-size:100%;color:#0000ff;"><u>The Levity Effect</u></span></a><br /><br /><p class="MsoNormal"><b><span style="TEXT-DECORATION: underline"></span></b><span style="LINE-HEIGHT: 115%;font-size:85%;" ></span></p><p class="MsoNormal"><span style="LINE-HEIGHT: 115%;font-size:85%;" >Special thanks to Joshua Williams for his help with this post.<o:p></o:p></span><br /></p><hr align="left" width="33%" style="font-size:78;"><br /><div id="edn1"><p class="MsoEndnoteText">[1] Robert <span class="blsp-spelling-error" id="SPELLING_ERROR_13">Pirsig</span>, Zen and the Art of Motorcycle Maintenance<br />[2] Wired Magazine Interview <a title="" href="//www.blogger.com/post-create.g?blogID=15045980#_ednref3" name="_edn3">http://blog.wired.com/games/2007/12/interview-super.html<br /></a>[3] Field of Dreams, 1989</p></div><div id="edn2"></div><div id="edn3"></div> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Google Testing Blog:Productivity Games – Using Games to Improve Quality&url=https://testing.googleblog.com/2008/06/productivity-games-using-games-to.html&via=googletesting'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://testing.googleblog.com/2008/06/productivity-games-using-games-to.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='comment-container'> <i class='comment-img material-icons'>  </i> <a href='https://testing.googleblog.com/2008/06/productivity-games-using-games-to.html#comments' style='font-weight: 500; text-decoration: underline;'>2 comments</a> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://testing.googleblog.com/2008/06/productivity-games-using-games-to.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> <span class='labels-caption'> Labels: </span> <span class='labels'> <a class='label' href='https://testing.googleblog.com/search/label/Patrick%20Copeland' rel='tag'> Patrick Copeland </a> </span> </div> </div> </div> <div class='post' data-id='2632154988414933193' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://testing.googleblog.com/2008/06/taming-beast-aka-how-to-test-ajax.html' itemprop='url' title='Taming the Beast (a.k.a. how to test AJAX applications) : Part 1'> Taming the Beast (a.k.a. how to test AJAX applications) : Part 1 </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Friday, June 13, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> Posted by Markus Clermont, John Thomas <br /><br />This is the first in a two part blog series titled 'Taming the Beast: How to test AJAX applications". In this part we discuss some philosophies around web application testing and how it should be done the 'right' way. In part 2, we walk through a real example of designing a test strategy for an AJAX application by going 'beyond the GUI.'<br /><br /><b id="v8mx1">Background<br /></b>Typically we address the problem of testing an AJAX application through a plethora of big end-to-end tests and (hopefully) high unit-test coverage. Here we outline the main problems with this approach and demonstrate an effective testing strategy for a sample GWT-based application which goes beyond "testing just through the GUI."<br /><br /><b id="ho:b">Problems with GUI-only testing</b><br /><div id="ji6d">In general testing through the GUI:<br /><ul id="hyz_1"><li id="hyz_2">is expensive (takes long to write the tests and execution is resource-intensive)<br /></li><li id="hyz_3">gives limited insight into the system</li><li id="hyz_4">often take only the 'happy paths' into account</li><li id="hyz_5">combines multiple aspects in a single test<br /></li><li id="hyz_7">is slow and brittle</li><li id="hyz_7">needs a lot of maintenance<br /></li><li id="hyz_7">is hard to debug</li></ul><br />And while unit tests don't suffer from many of these problems, they alone are not sufficient mainly because they:<br /><ul id="ji6d2"><li id="ji6d3">give little insight how the components interact with each other</li><li id="ji6d4">don't give confidence that the business logic and functionality of the system meets the requirements</li></ul></div><br /><b id="xup3">Solution</b><br />Although there is no 'one size fits all' solution, there are some basic principles we can use to solve the testing problem for web applications:<br /><div id="weg5" style="font-size:0.9em;"><ul id="j9-b"><li id="j9-b2"><span id="j9-b3" style="font-size:100%;">Invest in integration tests (identify the smallest sub-system)</span></li><li id="j9-b6"><span id="j9-b7" style="font-size:100%;">Separation of Concerns (don't do the set-up through the interface you are testing)</span></li><li id="j9-b10"><span id="j9-b11" style="font-size:100%;">Test each interface separately (mock out everything that you are not testing)</span></li><li id="j9-b14"><span id="j9-b15" style="font-size:100%;">Consider dependencies in production (figure out how dependencies can fail, and test that)<br /></span></li><li id="j9-b18"><span id="j9-b19" style="font-size:100%;">Use a mix of strategies and tools. There is no silver bullet.</span></li><li id="j9-b20"><span id="j9-b21" style="font-size:100%;"><b id="weg518">And no... you cannot scrap all of your end-to-end tests</b></span></li></ul></div><br /><b id="xup3">A recipe for testing goodness</b><br />Using the principles above we can build up a recipe for testing web applications. In the second part of our blog we will walk through each of these steps for a real web application.<br /><ol id="i1ex1"><li id="i1ex2">Explore the system's functionality</li><li id="i1ex3">Identify the system's architecture</li><li id="i1ex4">Identify the interfaces between components</li><li id="i1ex4">Identify dependencies and fault conditions</li><li id="i1ex4">For each function:</li></ol><ul style="margin-left: 40px;"><li>Identify the participating components</li><li>Identify potential problems</li><li>Test in isolation for problems</li><li>Create a 'happy path' test</li></ul><br /><b id="ikfc">End note: value of a test</b><br />A question commonly asked by developers when writing tests is, "is this really worth my time?" The short answer is "always!". Since fixing a bug is way more expensive than preventing it in the first place, writing good tests is always worth the time.<br /><br />While there are many different classifications of tests, the most common way of classifying them is based on their size and the areas of a product they test. Each test answers specific questions about the product:<br /><ul id="ge75"><li id="ge750">Unit test: is the method fulfilling its contract?</li><li id="ge751">Small integration test: Can two classes interact with each other?</li><li id="ge752"> Medium integration test: Is a class interacting properly with all its dependencies? Does it anticipate and handle errors correctly? Are the needed functions exposed on an API/GUI?</li><li id="ge752"> Sub-system test: Can two sub-systems interact with each other? Does one of them anticipate all errors of the other and does it deal with them appropriately?<br /></li><li id="ge752">System test: Does the entire system behave as expected?<br /></li></ul>Keeping this questions in mind, testing at various levels allows us to write more focused and meaningful tests. Remember that effective tests are those that provide quick <i id="m.5_">and</i> useful feedback, i.e. quickly identify issues and pin point the exact location of the issue.<br /><br />In the next episode we will walk through the recipe proposed above using a real web application. <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> Posted by Markus Clermont, John Thomas <br /><br />This is the first in a two part blog series titled 'Taming the Beast: How to test AJAX applications". In this part we discuss some philosophies around web application testing and how it should be done the 'right' way. In part 2, we walk through a real example of designing a test strategy for an AJAX application by going 'beyond the GUI.'<br /><br /><b id="v8mx1">Background<br /></b>Typically we address the problem of testing an AJAX application through a plethora of big end-to-end tests and (hopefully) high unit-test coverage. Here we outline the main problems with this approach and demonstrate an effective testing strategy for a sample GWT-based application which goes beyond "testing just through the GUI."<br /><br /><b id="ho:b">Problems with GUI-only testing</b><br /><div id="ji6d">In general testing through the GUI:<br /><ul id="hyz_1"><li id="hyz_2">is expensive (takes long to write the tests and execution is resource-intensive)<br /></li><li id="hyz_3">gives limited insight into the system</li><li id="hyz_4">often take only the 'happy paths' into account</li><li id="hyz_5">combines multiple aspects in a single test<br /></li><li id="hyz_7">is slow and brittle</li><li id="hyz_7">needs a lot of maintenance<br /></li><li id="hyz_7">is hard to debug</li></ul><br />And while unit tests don't suffer from many of these problems, they alone are not sufficient mainly because they:<br /><ul id="ji6d2"><li id="ji6d3">give little insight how the components interact with each other</li><li id="ji6d4">don't give confidence that the business logic and functionality of the system meets the requirements</li></ul></div><br /><b id="xup3">Solution</b><br />Although there is no 'one size fits all' solution, there are some basic principles we can use to solve the testing problem for web applications:<br /><div id="weg5" style="font-size:0.9em;"><ul id="j9-b"><li id="j9-b2"><span id="j9-b3" style="font-size:100%;">Invest in integration tests (identify the smallest sub-system)</span></li><li id="j9-b6"><span id="j9-b7" style="font-size:100%;">Separation of Concerns (don't do the set-up through the interface you are testing)</span></li><li id="j9-b10"><span id="j9-b11" style="font-size:100%;">Test each interface separately (mock out everything that you are not testing)</span></li><li id="j9-b14"><span id="j9-b15" style="font-size:100%;">Consider dependencies in production (figure out how dependencies can fail, and test that)<br /></span></li><li id="j9-b18"><span id="j9-b19" style="font-size:100%;">Use a mix of strategies and tools. There is no silver bullet.</span></li><li id="j9-b20"><span id="j9-b21" style="font-size:100%;"><b id="weg518">And no... you cannot scrap all of your end-to-end tests</b></span></li></ul></div><br /><b id="xup3">A recipe for testing goodness</b><br />Using the principles above we can build up a recipe for testing web applications. In the second part of our blog we will walk through each of these steps for a real web application.<br /><ol id="i1ex1"><li id="i1ex2">Explore the system's functionality</li><li id="i1ex3">Identify the system's architecture</li><li id="i1ex4">Identify the interfaces between components</li><li id="i1ex4">Identify dependencies and fault conditions</li><li id="i1ex4">For each function:</li></ol><ul style="margin-left: 40px;"><li>Identify the participating components</li><li>Identify potential problems</li><li>Test in isolation for problems</li><li>Create a 'happy path' test</li></ul><br /><b id="ikfc">End note: value of a test</b><br />A question commonly asked by developers when writing tests is, "is this really worth my time?" The short answer is "always!". Since fixing a bug is way more expensive than preventing it in the first place, writing good tests is always worth the time.<br /><br />While there are many different classifications of tests, the most common way of classifying them is based on their size and the areas of a product they test. Each test answers specific questions about the product:<br /><ul id="ge75"><li id="ge750">Unit test: is the method fulfilling its contract?</li><li id="ge751">Small integration test: Can two classes interact with each other?</li><li id="ge752"> Medium integration test: Is a class interacting properly with all its dependencies? Does it anticipate and handle errors correctly? Are the needed functions exposed on an API/GUI?</li><li id="ge752"> Sub-system test: Can two sub-systems interact with each other? Does one of them anticipate all errors of the other and does it deal with them appropriately?<br /></li><li id="ge752">System test: Does the entire system behave as expected?<br /></li></ul>Keeping this questions in mind, testing at various levels allows us to write more focused and meaningful tests. Remember that effective tests are those that provide quick <i id="m.5_">and</i> useful feedback, i.e. quickly identify issues and pin point the exact location of the issue.<br /><br />In the next episode we will walk through the recipe proposed above using a real web application. <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Google Testing Blog:Taming the Beast (a.k.a. how to test AJAX applications) : Part 1&url=https://testing.googleblog.com/2008/06/taming-beast-aka-how-to-test-ajax.html&via=googletesting'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://testing.googleblog.com/2008/06/taming-beast-aka-how-to-test-ajax.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='comment-container'> <i class='comment-img material-icons'>  </i> <a href='https://testing.googleblog.com/2008/06/taming-beast-aka-how-to-test-ajax.html#comments' style='font-weight: 500; text-decoration: underline;'>6 comments</a> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://testing.googleblog.com/2008/06/taming-beast-aka-how-to-test-ajax.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> <span class='labels-caption'> Labels: </span> <span class='labels'> <a class='label' href='https://testing.googleblog.com/search/label/John%20Thomas' rel='tag'> John Thomas </a> , <a class='label' href='https://testing.googleblog.com/search/label/Markus%20Clermont' rel='tag'> Markus Clermont </a> </span> </div> </div> </div> <div class='post' data-id='7184144255017647866' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://testing.googleblog.com/2008/06/tott-friends-you-can-depend-on.html' itemprop='url' title='TotT: Friends You Can Depend On'> TotT: Friends You Can Depend On </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Thursday, June 12, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <p>When you want to test code that depends on something that is too difficult or slow to use in a test environment, swap in a test double for the dependency.<br />A Dummy passes bogus input values around to satisfy an API.</p><br /><p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"><span style=" ;font-family:courier new, monospace;font-size:100%;">Item item = new Item(ITEM_NAME);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">ShoppingCart cart = new ShoppingCart();</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">cart.add(item, QUANTITY);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">assertEquals(QUANTITY, cart.getItem(ITEM_NAME)); </span></p><br /><p>A Stub overrides the real object and returns hard-coded values. Testing with stubs only is state-based testing; you exercise the system and then assert that the system is in an expected state. </p><br /><p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"><span style=" ;font-family:courier new, monospace;font-size:100%;">ItemPricer pricer = new ItemPricer() { <br /><span style=" ;font-family:courier new, monospace;font-size:100%;"> public BigDecimal getPrice(String name){ return PRICE; }</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">};</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">ShoppingCart cart = new ShoppingCart(pricer);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">cart.add(dummyItem, QUANTITY);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">assertEquals(QUANTITY*PRICE, cart.getCost(ITEM_NAME));</span></p><br /><p>A Mock can return values, but it also cares about the way its methods are called (“strict mocks” care about the order of method calls, whereas “lenient mocks” do not.) Testing with mocks is interaction-based testing; you set expectations on the mock, and the mock verifies the expectations as it is exercised. This example uses JMock to generate the mock (EasyMock is similar):</p><br /><p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"><span style=" ;font-family:courier new, monospace;font-size:100%;">Mockery context = new Mockery();</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">final ItemPricer pricer = context.mock(ItemPricer.class);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">context.checking(new Expectations() {{</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;"> one(pricer).getPrice(ITEM_NAME);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;"> will(returnValue(PRICE));</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">}});</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">ShoppingCart cart = new ShoppingCart(pricer);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">cart.add(dummyItem, QUANTITY);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">cart.getCost(ITEM_NAME); </span> <br /><span style=" ;font-family:courier new, monospace;font-size:100%;">context.assertIsSatisfied();</span></p><br /><p>A Spy serves the same purpose as a mock: returning values and recording calls to its methods. However, tests with spies are state-based rather than interaction-based, so the tests look more like stub style tests. </p><br /><p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"><span style=" ;font-family:courier new, monospace;font-size:100%;">TransactionLog log = new TransactionLogSpy();</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">ShoppingCart cart = new ShoppingCart(log);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">cart.add(dummyItem, QUANTITY);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">assertEquals(1, logSpy.getNumberOfTransactionsLogged()); </span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">assertEquals(QUANTITY*PRICE, log.getTransactionSubTotal(1));</span></p><br /><p>A Fake swaps out a real implementation with a simpler, fake implementation. The classic example is implementing an in-memory database. </p><br /><p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"><span style=" ;font-family:courier new, monospace;font-size:100%;">Repository<Transaction> repo = new InMemoryRepository<Transaction>();</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">ShoppingCart cart = new ShoppingCart(repo);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">cart.add(dummyItem, QUANTITY);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">assertEquals(1, repo.getTransactions(cart).Count); </span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">assertEquals(QUANTITY, repo.getById(cart.id()).getQuantity(ITEM_NAME));</span></p><br /><p>While this episode used Java for its examples, all of the above “friends” certainly exist in C++, Python, JavaScript, and probably in YOUR favorite language as well.</p><br /><p>Remember to download <a href="http://code.google.com/testing/TotT-2008-06-12.pdf">this episode</a> of Testing on the Toilet and post it in your office.</p> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <p>When you want to test code that depends on something that is too difficult or slow to use in a test environment, swap in a test double for the dependency.<br />A Dummy passes bogus input values around to satisfy an API.</p><br /><p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"><span style=" ;font-family:courier new, monospace;font-size:100%;">Item item = new Item(ITEM_NAME);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">ShoppingCart cart = new ShoppingCart();</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">cart.add(item, QUANTITY);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">assertEquals(QUANTITY, cart.getItem(ITEM_NAME)); </span></p><br /><p>A Stub overrides the real object and returns hard-coded values. Testing with stubs only is state-based testing; you exercise the system and then assert that the system is in an expected state. </p><br /><p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"><span style=" ;font-family:courier new, monospace;font-size:100%;">ItemPricer pricer = new ItemPricer() { <br /><span style=" ;font-family:courier new, monospace;font-size:100%;"> public BigDecimal getPrice(String name){ return PRICE; }</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">};</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">ShoppingCart cart = new ShoppingCart(pricer);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">cart.add(dummyItem, QUANTITY);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">assertEquals(QUANTITY*PRICE, cart.getCost(ITEM_NAME));</span></p><br /><p>A Mock can return values, but it also cares about the way its methods are called (“strict mocks” care about the order of method calls, whereas “lenient mocks” do not.) Testing with mocks is interaction-based testing; you set expectations on the mock, and the mock verifies the expectations as it is exercised. This example uses JMock to generate the mock (EasyMock is similar):</p><br /><p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"><span style=" ;font-family:courier new, monospace;font-size:100%;">Mockery context = new Mockery();</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">final ItemPricer pricer = context.mock(ItemPricer.class);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">context.checking(new Expectations() {{</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;"> one(pricer).getPrice(ITEM_NAME);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;"> will(returnValue(PRICE));</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">}});</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">ShoppingCart cart = new ShoppingCart(pricer);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">cart.add(dummyItem, QUANTITY);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">cart.getCost(ITEM_NAME); </span> <br /><span style=" ;font-family:courier new, monospace;font-size:100%;">context.assertIsSatisfied();</span></p><br /><p>A Spy serves the same purpose as a mock: returning values and recording calls to its methods. However, tests with spies are state-based rather than interaction-based, so the tests look more like stub style tests. </p><br /><p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"><span style=" ;font-family:courier new, monospace;font-size:100%;">TransactionLog log = new TransactionLogSpy();</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">ShoppingCart cart = new ShoppingCart(log);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">cart.add(dummyItem, QUANTITY);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">assertEquals(1, logSpy.getNumberOfTransactionsLogged()); </span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">assertEquals(QUANTITY*PRICE, log.getTransactionSubTotal(1));</span></p><br /><p>A Fake swaps out a real implementation with a simpler, fake implementation. The classic example is implementing an in-memory database. </p><br /><p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"><span style=" ;font-family:courier new, monospace;font-size:100%;">Repository<Transaction> repo = new InMemoryRepository<Transaction>();</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">ShoppingCart cart = new ShoppingCart(repo);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">cart.add(dummyItem, QUANTITY);</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">assertEquals(1, repo.getTransactions(cart).Count); </span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">assertEquals(QUANTITY, repo.getById(cart.id()).getQuantity(ITEM_NAME));</span></p><br /><p>While this episode used Java for its examples, all of the above “friends” certainly exist in C++, Python, JavaScript, and probably in YOUR favorite language as well.</p><br /><p>Remember to download <a href="http://code.google.com/testing/TotT-2008-06-12.pdf">this episode</a> of Testing on the Toilet and post it in your office.</p> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Google Testing Blog:TotT: Friends You Can Depend On&url=https://testing.googleblog.com/2008/06/tott-friends-you-can-depend-on.html&via=googletesting'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://testing.googleblog.com/2008/06/tott-friends-you-can-depend-on.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='comment-container'> <i class='comment-img material-icons'>  </i> <a href='https://testing.googleblog.com/2008/06/tott-friends-you-can-depend-on.html#comments' style='font-weight: 500; text-decoration: underline;'>4 comments</a> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://testing.googleblog.com/2008/06/tott-friends-you-can-depend-on.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> <span class='labels-caption'> Labels: </span> <span class='labels'> <a class='label' href='https://testing.googleblog.com/search/label/TotT' rel='tag'> TotT </a> </span> </div> </div> </div> <div class='post' data-id='958832703938991511' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://testing.googleblog.com/2008/06/3-days-left-for-gtac-proposals.html' itemprop='url' title='3 days left for GTAC Proposals!'> 3 days left for GTAC Proposals! </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Tuesday, June 03, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> A brief reminder that there are only three days left to submit proposals for this year's Google Test Automation Conference. The proposal deadline is June 6th, after which the selection process will begin.<br /><br />The Call For Proposals announcement is available at the Google Testing Blog <a href="http://googletesting.blogspot.com/2008/04/gtac-call-for-proposals.html">here</a>.<a href="http://googletesting.blogspot.com/2008/04/gtac-call-for-proposals.html" target="_blank"></a><br /><br />See you in October!<br /><span style="color:#888888;">Lydia Ash<br />GTAC Conference Chair - 2008</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> A brief reminder that there are only three days left to submit proposals for this year's Google Test Automation Conference. The proposal deadline is June 6th, after which the selection process will begin.<br /><br />The Call For Proposals announcement is available at the Google Testing Blog <a href="http://googletesting.blogspot.com/2008/04/gtac-call-for-proposals.html">here</a>.<a href="http://googletesting.blogspot.com/2008/04/gtac-call-for-proposals.html" target="_blank"></a><br /><br />See you in October!<br /><span style="color:#888888;">Lydia Ash<br />GTAC Conference Chair - 2008</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </noscript> </div> </div> <div class='share'> <span class='twitter-custom social-wrapper' data-href='http://twitter.com/share?text=Google Testing Blog:3 days left for GTAC Proposals!&url=https://testing.googleblog.com/2008/06/3-days-left-for-gtac-proposals.html&via=googletesting'> <img alt='Share on Twitter' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_twitter_black_24dp.png' width='24'/> </span> <span class='fb-custom social-wrapper' data-href='https://www.facebook.com/sharer.php?u=https://testing.googleblog.com/2008/06/3-days-left-for-gtac-proposals.html'> <img alt='Share on Facebook' height='24' src='https://www.gstatic.com/images/icons/material/system/2x/post_facebook_black_24dp.png' width='24'/> </span> </div> <div class='comment-container'> <i class='comment-img material-icons'>  </i> <a href='https://testing.googleblog.com/2008/06/3-days-left-for-gtac-proposals.html#comments' style='font-weight: 500; text-decoration: underline;'>No comments</a> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://testing.googleblog.com/2008/06/3-days-left-for-gtac-proposals.html' data-viewtype='FILTERED_POSTMOD'></div> <a href='https://plus.google.com/112374322230920073195' rel='author' style='display:none;'> Google </a> <div class='label-footer'> <span class='labels-caption'> Labels: </span> <span class='labels'> <a class='label' href='https://testing.googleblog.com/search/label/GTAC' rel='tag'> GTAC </a> </span> </div> </div> </div> <div class='blog-pager' id='blog-pager'> <a class='home-link' href='https://testing.googleblog.com/'> <i class='material-icons'>  </i> </a> <span id='blog-pager-newer-link'> <a class='blog-pager-newer-link' href='https://testing.googleblog.com/search?updated-max=2008-07-21T15:31:00-07:00&max-results=5&reverse-paginate=true' id='Blog1_blog-pager-newer-link' title='Newer Posts'> <i class='material-icons'>  </i> </a> </span> <span id='blog-pager-older-link'> <a class='blog-pager-older-link' href='https://testing.googleblog.com/search?updated-max=2008-06-03T20:44:00-07:00&max-results=5' id='Blog1_blog-pager-older-link' title='Older Posts'> <i class='material-icons'>  </i> </a> </span> </div> <div class='clear'></div> </div></div> </div> </div> <div class='col-right'> <div class='section' id='sidebar-top'><div class='widget HTML' data-version='1' id='HTML8'> <div class='widget-content'> <div class='searchBox'> <input type='text' title='Search This Blog' placeholder='Search blog ...' /> </div> </div> <div class='clear'></div> </div> </div> <div id='aside'> <div class='section' id='sidebar'><div class='widget Label' data-version='1' id='Label1'> <div class='tab'> <img class='sidebar-icon' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAYpJREFUeNrs2aFuwzAQBmAvKRkMKRjZA4QMDJaWFgyMjuzFRg37DIUlA3uFkoGQSaWzJU+tpri5O9+l/zSfdFJlpe59yTmyVedq1PjfcZMZ70NuQnaF8w8htyE/rABtpviXkLcK88c5HhLkMBfgVan43zfFBNGMjHVGT/s55KP2pAvidbGHd+nzKt1RKSLG3rKF1iPFv6UWiPke8i7kEqGdGsI1O+LYVdqJAjgirwkKYD0ytkJBUNbAMvX8V3q9PhUsYvU1sWD8SO/sQvx2ahxOiNoJCSBCoAHYCEQAC4EKICOQASQEOmAS8RcAFxFN5hiIiugpgC3wk9hQAHH/70EBHXUN7IER5EWMiBgo2+nzOKQv9SCAeEM/OQAkhE/ncccFICB87qzQMia5FsJfOui0zMnmRvipU1ormHQuxGTxUsAcCFLxJQBLBLn4UoAFglW8BkATwS5eC6CBEBWvCShBiIvXBkgQRcVbADiI4uKtABSESvGWgB9EzHt3+tNwyO0qa9SoIYtvAQYAqDJhaWWeMecAAAAASUVORK5CYII='/> <h2> Labels </h2> <i class='material-icons arrow'>  </i> </div> <div class='widget-content list-label-widget-content'> <ul> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/TotT'> TotT </a> <span dir='ltr'> 104 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/GTAC'> GTAC </a> <span dir='ltr'> 61 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/James%20Whittaker'> James Whittaker </a> <span dir='ltr'> 42 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Misko%20Hevery'> Misko Hevery </a> <span dir='ltr'> 32 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Code%20Health'> Code Health </a> <span dir='ltr'> 31 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Anthony%20Vallone'> Anthony Vallone </a> <span dir='ltr'> 27 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Patrick%20Copeland'> Patrick Copeland </a> <span dir='ltr'> 23 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Jobs'> Jobs </a> <span dir='ltr'> 18 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Andrew%20Trenk'> Andrew Trenk </a> <span dir='ltr'> 13 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/C%2B%2B'> C++ </a> <span dir='ltr'> 11 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Patrik%20H%C3%B6glund'> Patrik Höglund </a> <span dir='ltr'> 8 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/JavaScript'> JavaScript </a> <span dir='ltr'> 7 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Allen%20Hutchison'> Allen Hutchison </a> <span dir='ltr'> 6 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/George%20Pirocanac'> George Pirocanac </a> <span dir='ltr'> 6 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Zhanyong%20Wan'> Zhanyong Wan </a> <span dir='ltr'> 6 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Harry%20Robinson'> Harry Robinson </a> <span dir='ltr'> 5 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Java'> Java </a> <span dir='ltr'> 5 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Julian%20Harty'> Julian Harty </a> <span dir='ltr'> 5 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Adam%20Bender'> Adam Bender </a> <span dir='ltr'> 4 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Alberto%20Savoia'> Alberto Savoia </a> <span dir='ltr'> 4 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Ben%20Yu'> Ben Yu </a> <span dir='ltr'> 4 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Erik%20Kuefler'> Erik Kuefler </a> <span dir='ltr'> 4 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Philip%20Zembrod'> Philip Zembrod </a> <span dir='ltr'> 4 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Shyam%20Seshadri'> Shyam Seshadri </a> <span dir='ltr'> 4 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Chrome'> Chrome </a> <span dir='ltr'> 3 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Dillon%20Bly'> Dillon Bly </a> <span dir='ltr'> 3 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/John%20Thomas'> John Thomas </a> <span dir='ltr'> 3 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Lesley%20Katzen'> Lesley Katzen </a> <span dir='ltr'> 3 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Marc%20Kaplan'> Marc Kaplan </a> <span dir='ltr'> 3 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Markus%20Clermont'> Markus Clermont </a> <span dir='ltr'> 3 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Max%20Kanat-Alexander'> Max Kanat-Alexander </a> <span dir='ltr'> 3 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Sonal%20Shah'> Sonal Shah </a> <span dir='ltr'> 3 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/APIs'> APIs </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Abhishek%20Arya'> Abhishek Arya </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Alan%20Myrvold'> Alan Myrvold </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Alek%20Icev'> Alek Icev </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Android'> Android </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/April%20Fools'> April Fools </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Chaitali%20Narla'> Chaitali Narla </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Chris%20Lewis'> Chris Lewis </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Chrome%20OS'> Chrome OS </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Diego%20Salas'> Diego Salas </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Dori%20Reuveni'> Dori Reuveni </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Jason%20Arbon'> Jason Arbon </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Jochen%20Wuttke'> Jochen Wuttke </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Kostya%20Serebryany'> Kostya Serebryany </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Marc%20Eaddy'> Marc Eaddy </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Marko%20Ivankovi%C4%87'> Marko Ivanković </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Mobile'> Mobile </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Oliver%20Chang'> Oliver Chang </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Simon%20Stewart'> Simon Stewart </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Stefan%20Kennedy'> Stefan Kennedy </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Test%20Flakiness'> Test Flakiness </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Titus%20Winters'> Titus Winters </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Tony%20Voellm'> Tony Voellm </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/WebRTC'> WebRTC </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Yiming%20Sun'> Yiming Sun </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Yvette%20Nameth'> Yvette Nameth </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Zuri%20Kemp'> Zuri Kemp </a> <span dir='ltr'> 2 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Aaron%20Jacobs'> Aaron Jacobs </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Adam%20Porter'> Adam Porter </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Adam%20Raider'> Adam Raider </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Adel%20Saoud'> Adel Saoud </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Alan%20Faulkner'> Alan Faulkner </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Alex%20Eagle'> Alex Eagle </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Amy%20Fu'> Amy Fu </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Anantha%20Keesara'> Anantha Keesara </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Antoine%20Picard'> Antoine Picard </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/App%20Engine'> App Engine </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Ari%20Shamash'> Ari Shamash </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Arif%20Sukoco'> Arif Sukoco </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Benjamin%20Pick'> Benjamin Pick </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Bob%20Nystrom'> Bob Nystrom </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Bruce%20Leban'> Bruce Leban </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Carlos%20Arguelles'> Carlos Arguelles </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Carlos%20Israel%20Ortiz%20Garc%C3%ADa'> Carlos Israel Ortiz García </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Cathal%20Weakliam'> Cathal Weakliam </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Christopher%20Semturs'> Christopher Semturs </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Clay%20Murphy'> Clay Murphy </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Dagang%20Wei'> Dagang Wei </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Dan%20Maksimovich'> Dan Maksimovich </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Dan%20Shi'> Dan Shi </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Dan%20Willemsen'> Dan Willemsen </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Dave%20Chen'> Dave Chen </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Dave%20Gladfelter'> Dave Gladfelter </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/David%20Bendory'> David Bendory </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/David%20Mandelberg'> David Mandelberg </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Derek%20Snyder'> Derek Snyder </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Diego%20Cavalcanti'> Diego Cavalcanti </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Dmitry%20Vyukov'> Dmitry Vyukov </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Eduardo%20Bravo%20Ortiz'> Eduardo Bravo Ortiz </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Ekaterina%20Kamenskaya'> Ekaterina Kamenskaya </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Elliott%20Karpilovsky'> Elliott Karpilovsky </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Elliotte%20Rusty%20Harold'> Elliotte Rusty Harold </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Espresso'> Espresso </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Felipe%20Sodr%C3%A9'> Felipe Sodré </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Francois%20Aube'> Francois Aube </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Gene%20Volovich'> Gene Volovich </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Google%2B'> Google+ </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Goran%20Petrovic'> Goran Petrovic </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Goranka%20Bjedov'> Goranka Bjedov </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Hank%20Duan'> Hank Duan </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Havard%20Rast%20Blok'> Havard Rast Blok </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Hongfei%20Ding'> Hongfei Ding </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Jason%20Elbaum'> Jason Elbaum </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Jason%20Huggins'> Jason Huggins </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Jay%20Han'> Jay Han </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Jeff%20Hoy'> Jeff Hoy </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Jeff%20Listfield'> Jeff Listfield </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Jessica%20Tomechak'> Jessica Tomechak </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Jim%20Reardon'> Jim Reardon </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Joe%20Allan%20Muharsky'> Joe Allan Muharsky </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Joel%20Hynoski'> Joel Hynoski </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/John%20Micco'> John Micco </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/John%20Penix'> John Penix </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Jonathan%20Rockway'> Jonathan Rockway </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Jonathan%20Velasquez'> Jonathan Velasquez </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Josh%20Armour'> Josh Armour </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Julie%20Ralph'> Julie Ralph </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Kai%20Kent'> Kai Kent </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Kanu%20Tewary'> Kanu Tewary </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Karin%20Lundberg'> Karin Lundberg </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Kaue%20Silveira'> Kaue Silveira </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Kevin%20Bourrillion'> Kevin Bourrillion </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Kevin%20Graney'> Kevin Graney </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Kirkland'> Kirkland </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Kurt%20Alfred%20Kluever'> Kurt Alfred Kluever </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Manjusha%20Parvathaneni'> Manjusha Parvathaneni </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Marek%20Kiszkis'> Marek Kiszkis </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Marius%20Latinis'> Marius Latinis </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Mark%20Ivey'> Mark Ivey </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Mark%20Manley'> Mark Manley </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Mark%20Striebeck'> Mark Striebeck </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Matt%20Lowrie'> Matt Lowrie </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Meredith%20Whittaker'> Meredith Whittaker </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Michael%20Bachman'> Michael Bachman </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Michael%20Klepikov'> Michael Klepikov </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Mike%20Aizatsky'> Mike Aizatsky </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Mike%20Wacker'> Mike Wacker </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Mona%20El%20Mahdy'> Mona El Mahdy </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Noel%20Yap'> Noel Yap </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Palak%20Bansal'> Palak Bansal </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Patricia%20Legaspi'> Patricia Legaspi </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Per%20Jacobsson'> Per Jacobsson </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Peter%20Arrenbrecht'> Peter Arrenbrecht </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Peter%20Spragins'> Peter Spragins </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Phil%20Norman'> Phil Norman </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Phil%20Rollet'> Phil Rollet </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Pooja%20Gupta'> Pooja Gupta </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Project%20Showcase'> Project Showcase </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Radoslav%20Vasilev'> Radoslav Vasilev </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Rajat%20Dewan'> Rajat Dewan </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Rajat%20Jain'> Rajat Jain </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Rich%20Martin'> Rich Martin </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Richard%20Bustamante'> Richard Bustamante </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Roshan%20Sembacuttiaratchy'> Roshan Sembacuttiaratchy </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Ruslan%20Khamitov'> Ruslan Khamitov </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Sam%20Lee'> Sam Lee </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Sean%20Jordan'> Sean Jordan </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Sebastian%20D%C3%B6rner'> Sebastian Dörner </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Sharon%20Zhou'> Sharon Zhou </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Shiva%20Garg'> Shiva Garg </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Siddartha%20Janga'> Siddartha Janga </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Simran%20Basi'> Simran Basi </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Stan%20Chan'> Stan Chan </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Stephen%20Ng'> Stephen Ng </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Tejas%20Shah'> Tejas Shah </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Test%20Analytics'> Test Analytics </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Test%20Engineer'> Test Engineer </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Tim%20Lyakhovetskiy'> Tim Lyakhovetskiy </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Tom%20O%27Neill'> Tom O'Neill </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/Vojta%20J%C3%ADna'> Vojta Jína </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/automation'> automation </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/dead%20code'> dead code </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/iOS'> iOS </a> <span dir='ltr'> 1 </span> </li> <li> <a dir='ltr' href='https://testing.googleblog.com/search/label/mutation%20testing'> mutation testing </a> <span dir='ltr'> 1 </span> </li> </ul> <div class='clear'></div> </div> </div><div class='widget BlogArchive' data-version='1' id='BlogArchive1'> <div class='tab'> <i class='material-icons icon'>  </i> <h2> Archive </h2> <i class='material-icons arrow'>  </i> </div> <div class='widget-content'> <div id='ArchiveList'> <div id='BlogArchive1_ArchiveList'> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2025/'> 2025 </a> <span class='post-count' dir='ltr'>(1)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2025/01/'> Jan </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2024/'> 2024 </a> <span class='post-count' dir='ltr'>(13)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2024/12/'> Dec </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2024/10/'> Oct </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2024/09/'> Sep </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2024/08/'> Aug </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2024/07/'> Jul </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2024/05/'> May </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2024/04/'> Apr </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2024/03/'> Mar </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2024/02/'> Feb </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2023/'> 2023 </a> <span class='post-count' dir='ltr'>(14)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2023/12/'> Dec </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2023/11/'> Nov </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2023/10/'> Oct </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2023/09/'> Sep </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2023/08/'> Aug </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2023/04/'> Apr </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2022/'> 2022 </a> <span class='post-count' dir='ltr'>(2)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2022/02/'> Feb </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2021/'> 2021 </a> <span class='post-count' dir='ltr'>(3)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2021/06/'> Jun </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2021/04/'> Apr </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2021/03/'> Mar </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2020/'> 2020 </a> <span class='post-count' dir='ltr'>(8)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2020/12/'> Dec </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2020/11/'> Nov </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2020/10/'> Oct </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2020/08/'> Aug </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2020/07/'> Jul </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2020/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2019/'> 2019 </a> <span class='post-count' dir='ltr'>(4)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2019/12/'> Dec </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2019/11/'> Nov </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2019/07/'> Jul </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2019/01/'> Jan </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2018/'> 2018 </a> <span class='post-count' dir='ltr'>(7)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2018/11/'> Nov </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2018/09/'> Sep </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2018/07/'> Jul </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2018/06/'> Jun </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2018/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2018/02/'> Feb </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2017/'> 2017 </a> <span class='post-count' dir='ltr'>(17)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2017/12/'> Dec </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2017/11/'> Nov </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2017/10/'> Oct </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2017/09/'> Sep </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2017/08/'> Aug </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2017/07/'> Jul </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2017/06/'> Jun </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2017/05/'> May </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2017/04/'> Apr </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2017/02/'> Feb </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2017/01/'> Jan </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2016/'> 2016 </a> <span class='post-count' dir='ltr'>(15)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2016/12/'> Dec </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2016/11/'> Nov </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2016/10/'> Oct </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2016/09/'> Sep </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2016/08/'> Aug </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2016/06/'> Jun </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2016/05/'> May </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2016/04/'> Apr </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2016/03/'> Mar </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2016/02/'> Feb </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2015/'> 2015 </a> <span class='post-count' dir='ltr'>(14)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2015/12/'> Dec </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2015/11/'> Nov </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2015/10/'> Oct </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2015/08/'> Aug </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2015/06/'> Jun </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2015/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2015/04/'> Apr </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2015/03/'> Mar </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2015/02/'> Feb </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2015/01/'> Jan </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2014/'> 2014 </a> <span class='post-count' dir='ltr'>(24)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2014/12/'> Dec </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2014/11/'> Nov </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2014/10/'> Oct </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2014/09/'> Sep </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2014/08/'> Aug </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2014/07/'> Jul </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2014/06/'> Jun </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2014/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2014/04/'> Apr </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2014/03/'> Mar </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2014/02/'> Feb </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2014/01/'> Jan </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2013/'> 2013 </a> <span class='post-count' dir='ltr'>(16)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2013/12/'> Dec </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2013/11/'> Nov </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2013/10/'> Oct </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2013/08/'> Aug </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2013/07/'> Jul </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2013/06/'> Jun </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2013/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2013/04/'> Apr </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2013/03/'> Mar </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2013/01/'> Jan </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2012/'> 2012 </a> <span class='post-count' dir='ltr'>(11)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2012/12/'> Dec </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2012/11/'> Nov </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2012/10/'> Oct </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2012/09/'> Sep </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2012/08/'> Aug </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2011/'> 2011 </a> <span class='post-count' dir='ltr'>(39)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2011/11/'> Nov </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2011/10/'> Oct </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2011/09/'> Sep </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2011/08/'> Aug </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2011/07/'> Jul </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2011/06/'> Jun </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2011/05/'> May </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2011/04/'> Apr </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2011/03/'> Mar </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2011/02/'> Feb </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2011/01/'> Jan </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2010/'> 2010 </a> <span class='post-count' dir='ltr'>(37)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2010/12/'> Dec </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2010/11/'> Nov </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2010/10/'> Oct </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2010/09/'> Sep </a> <span class='post-count' dir='ltr'>(8)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2010/08/'> Aug </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2010/07/'> Jul </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2010/06/'> Jun </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2010/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2010/04/'> Apr </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2010/03/'> Mar </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2010/02/'> Feb </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2010/01/'> Jan </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2009/'> 2009 </a> <span class='post-count' dir='ltr'>(54)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2009/12/'> Dec </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2009/11/'> Nov </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2009/10/'> Oct </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2009/09/'> Sep </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2009/08/'> Aug </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2009/07/'> Jul </a> <span class='post-count' dir='ltr'>(15)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2009/06/'> Jun </a> <span class='post-count' dir='ltr'>(8)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2009/05/'> May </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2009/04/'> Apr </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2009/02/'> Feb </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2009/01/'> Jan </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate expanded'> <a class='toggle' href='javascript:void(0)'> <span class='zippy toggle-open'> ▼  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2008/'> 2008 </a> <span class='post-count' dir='ltr'>(75)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2008/12/'> Dec </a> <span class='post-count' dir='ltr'>(6)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2008/11/'> Nov </a> <span class='post-count' dir='ltr'>(8)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2008/10/'> Oct </a> <span class='post-count' dir='ltr'>(9)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2008/09/'> Sep </a> <span class='post-count' dir='ltr'>(8)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2008/08/'> Aug </a> <span class='post-count' dir='ltr'>(9)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2008/07/'> Jul </a> <span class='post-count' dir='ltr'>(9)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate expanded'> <a class='toggle' href='javascript:void(0)'> <span class='zippy toggle-open'> ▼  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2008/06/'> Jun </a> <span class='post-count' dir='ltr'>(6)</span> <ul class='posts'> <li> <a href='https://testing.googleblog.com/2008/06/defeat-static-cling.html'> TotT: Defeat "Static Cling" </a> </li> <li> <a href='https://testing.googleblog.com/2008/06/test-engineering-class-project-at-uc.html'> Test Engineering Class Project at UC-Irivine </a> </li> <li> <a href='https://testing.googleblog.com/2008/06/productivity-games-using-games-to.html'> Productivity Games – Using Games to Improve Quality </a> </li> <li> <a href='https://testing.googleblog.com/2008/06/taming-beast-aka-how-to-test-ajax.html'> Taming the Beast (a.k.a. how to test AJAX applicat... </a> </li> <li> <a href='https://testing.googleblog.com/2008/06/tott-friends-you-can-depend-on.html'> TotT: Friends You Can Depend On </a> </li> <li> <a href='https://testing.googleblog.com/2008/06/3-days-left-for-gtac-proposals.html'> 3 days left for GTAC Proposals! </a> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2008/05/'> May </a> <span class='post-count' dir='ltr'>(6)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2008/04/'> Apr </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2008/03/'> Mar </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2008/02/'> Feb </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2008/01/'> Jan </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2007/'> 2007 </a> <span class='post-count' dir='ltr'>(41)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2007/10/'> Oct </a> <span class='post-count' dir='ltr'>(6)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2007/09/'> Sep </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2007/08/'> Aug </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2007/07/'> Jul </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2007/06/'> Jun </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2007/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2007/04/'> Apr </a> <span class='post-count' dir='ltr'>(7)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2007/03/'> Mar </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2007/02/'> Feb </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2007/01/'> Jan </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> </li> </ul> </div> </div> <div class='clear'></div> </div> </div><div class='widget HTML' data-version='1' id='HTML6'> <div class='widget-content'> <a href="http://googletesting.blogspot.com/atom.xml"> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAihJREFUeNrsWa9Pw0AU7viRMDFRBAkzJDMIBIhJJhCzk7NILIqMv4AEhdz+BCY3OYssAlGBoAJREpZwAlHEBO8lr8nSvNeVbu1dyX3JlzTrXfa+u/e9d7c5joWFhYVO1Fa8PwH2gK6m+BRwAvSlAdsrgr8E1jUuMH73GTAEzrkBWymTewZlihhLmgDXIAFuHgGVQOUF7OSYM1p6PgTuA1vAZlUEvAnPdapcMY0VICECekQ0XRfYrqoHsAGNgXfAoMomRiFDEhOZkkL3S88hMaB2LwXp0bj+ps2edpToZpjfoIDQtBeU+xjoDzP2G/gCPKZ5f8WsCAFJoJgOCcFdWSTeL9YQMSvTA1h9BkI5jaiXhLpSCL/8mVZY0UpyJ9ZdOkniu1dmJ96BpzQu9w6s28gcOq9j6pwLdR8/36NK5CQKwJSMrb2MhhSglBpt4UjsrdsnNu0B3J0HCozbCc4TjyY2srEgos/4RQljCzNxl4ireQD8FOq+T+W0mTB2g7njhlR+Sy2jsXFvU658U8YTbeaGpdIu7mWkEAq5ZtIjIhFZdtfX7QHckSvB2B6zC3VdAkZk0kAQwaXTk/CzTXK3wjIExCs6ZJpTnE4uY1KV+KzFzA3KTiFPENHJkOPcsfpLhwe4btoSuvUqAR+6TOxlCE6ZfKUsJLgsqGW8OpqAGx2X+sLxrwUog+JUeQRMDBIwyXOcnlPtPnL0/UsT/8LnOxYWFhZG4leAAQAAQHEaYuzHbAAAAABJRU5ErkJggg==" class="sidebar-icon" /> <h2>Feed</h2> </a> </div> <div class='clear'></div> </div></div> <div class='section' id='sidebar-bottom'><div class='widget HTML' data-version='1' id='HTML9'> <div class='widget-content'> <a href='http://cloud.feedly.com/#subscription%2Ffeed%2Fhttp%3A%2F%2Fgoogletesting.blogspot.com%2Ffeeds%2Fposts%2Fdefault' target='blank'><img id="feedlyFollow" src="https://lh3.googleusercontent.com/blogger_img_proxy/AEn0k_v_bQ_vR7KeVNMDFhAGN2F6t94i9dYU-QyJtHk6TO_Bb4WmpAU7PaiPQuh-sNoU1-m7wAdxr51UtYQBtGzO6N9Q1IMoxu_UrnmJBATIFGO_8IZ6bWScgMymHSOUSelg6wg_z4ukk8KCKPTnhV1SK_M=s0-d" alt="follow us in feedly" width="66" height="20"></a> <div class="share followgooglewrapper"> <button data-href="https://twitter.com/intent/follow?original_referer=http://googletesting.blogspot.com/&screen_name=googletesting" onclick='sharingPopup(this);' id='twitter-share'><span class="twitter-follow">Follow @googletesting</span></button> <script> function sharingPopup (button) { var url = button.getAttribute("data-href"); window.open( url,'popUpWindow','height=500,width=500,left=10,top=10,resizable=yes,scrollbars=yes,toolbar=yes,menubar=no,location=no,directories=no,status=yes'); } </script> </div> </div> <div class='clear'></div> </div></div> </div> </div> <div style='clear:both;'></div> </div> <!-- Footer --> <div class='google-footer-outer loading'> <div id='google-footer'> <a href='//www.google.com/'> <img class='google-logo-dark' height='36' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALgAAABICAYAAABFoT/eAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAACLVJREFUeNrsXd+L20YQ3vOprdLqiMXFXE2qB7dcwEcTSB7ykIc+9A/PQx/yEMq1TWhNuYIpJriNr7XpmZ5IxFEvmW2EKs3Ornb1w50PxIFP0kiz387OzM6uhGAwGAxGP3Ho+f7x7ri1O7LdccPqZjSNA4dEHsLfaHcEFedJom93x9Xu2OyOFTcBo6sED3fHZHeMEELrkAHJF0B8Rr+gDFsZ5n0luLTQ95AXs4W06D/tjpR50xtM4CjD0y48YGB4rnyZxNOzyA7zBHr+nLnDaJLg0mo/ALekCasg3Z4XbM0ZdTEgnDPeHY8bIne+Qz2GvwyGNwsuyT218KWvIIBMcwGpLiipcolecjMxfBDchNyS1EvxLiOSIecp31q6IJ/C3yrIrMqMm4jhg+AxkdwbIO3aUO4KjqqMjCT3uaazMBhWBJfuxH3CtRfiXf66DhSRZWbmlMnNaILgZxrXJQO/eO3wORZwvwm4JUxuhheCjzVBYAbW1ces45YDSoZrFNOEE835M8FT6oyeEnws8Fz3QnBxFKPHBMem4GU+m6fPGb0leCTwWcM5B36MPgeZI01gudyDdw3hPeXfo8L/rmCUWnuMMdqUL2WqWeRbhf+twfVsO7YagZGNC79fw7OthEVtkiJ4jJzTd3KPwf3CRqhhiTu23AP5sl0/0xiwISQXpNwLIJK87mHF+U8ddzzdmgKlGzlPYjyxGJQouIhNT4k9AqWEFkqfguIvagTWbcq3KW1WE3xS3m8NtA9WS451xofwjKT5kkDoK/b6mDk5FfXr1lWDL4BofZEv2/SRsK/EHGlGdBdu8QNRb8HMCFwt7Yy3DDI/QP7fx5z3VLhdlJEIs4rKNuXXJXdxZPdB7kfCzWqwCO4V1LHgLjInX3tQ1KzCR52Cz+vDj1dydeRuS74rcvs2Pi6fT5H8OaaUQPQPYcWwRSGXyhhscn5dpAnEFMkuEZetbfkTAnlSuH4DxisE+aMGeJAQ3lFl7C4LJE6QWCaCd583ORQ1jYAwjFctal7nOs2ZZvicwvlZx+RHGrcoAwKUVX8uwcc/9TT65INeDOr5shL9LDRB6QTeIy3zwfdh3WOi6axLCEhSjXU7F3h6LqggUtvyJxpynwu8tDkD98fXApOxRj8zoZ9MnGveYVIVZKaGrkBXCY65BCYNN9NkjpKOyQ81Q79JgdxS+Jn3SDTEXRI7SWzaiSTB32oI3nU3BvMfM0urhOVYgwKhuiAfc4tM07wXwm1ZRoQYSl2NUwiu01fEAHVcpixd745FvVz4dzUUc0o8rwoLy8ZSwU6CyFx1RP5II9+1bFPEFs9HWbNLiimDXE+vCm7u1CS47cofzD3aEhVY57mxRo5zlqdt+RFC1JUH2S7bcVXg4liTMakaBZZVxiTICRoivcn1sEUBlk24JmaC6kxUbYmWoqvyfck2xZGGnDFYa9MMzkYQ1ijkCX6qidybrgePiQ0QIQqoi6qRLeqQfIoRsEHaQJLBdHOnLGetSdm/IPcymJuS1PAnbQPH0MOw/39C1vL11DiLOqIsbDI8QcHvGiLnySi2qUXBicaqUSxN5LEB0g7Jt3ENXJLPJ5S1tnaZBoWbpRqrmjRE7qHmpSmNHdQcYrEUadoh+TbBnc9ri7iycI1kzPeNcLDIvbiqXpez9Tmdq6zGREPuzECBoxrPMiI2WtvyNwhJba2wy3JZ6ky5dD1lSvmZS3e4SPA1wcf1VTFHKX+cGwZzdUYcqpvUtvwrD/InDttVlyZeAKlNN5MKbAiurHhKIPlUuJvlTCCiDjSKSCsUmCFWbGLZwCESfK07JB8LvMYWVtw0D00JEHV8Mq2HkqPbE0oHLvvK2g0o8ETg+4cfwTlZDT9JDoWygu4uQQE/ivIvtcnfPkaCqhiupz7jWOAzqL/vjtcdkv9G4MVMt+EaylfuImiPAXEUjRF3pjjaHiPPZ6If9TGGAO4ZY0am6jOCb+DQ+ZCqLkIpOIPrdNfIjnFPY6nyFut7TS/fanrziOBOKMupKw94WaLMtuVnSFt9CPrWWdJE6PeltCX432DEBoh+5Dv8RRhdis8YAv9uyq4/JAwtlEApgBe9Cw9xDD3tdk4Jn0MDfiHwPHcRPxBePCMER3GuIx7kGlv9fkZ4V9lolx2Uv4X7hEj7qJ3LDoAMGbTRMRibu4L2xQ8bgt8AyU+Q+x7nYrvDnH4iuO5LxKsYwPVbkPMvKF9Zky9wXzRfVWizi62r9X5VHf55h+WHhDjGBZ4WRhyTr6z5SlCoLMxLSpBZFsQ9F80uQFbF/6aFWi+Ev51vzzsuX+msyzuQXXjUz8zEBy+zpq9yweXAoxJW4JbYrDS6gYDqGHxPl+TKeiBfxj9/EBIElPYeOA4y8/qRQfknjvSzgRgtq0Pw/M1eQeMdOSb2Bnrhr6Led+1vcp2x7oTFHMnedFW+Ivlty062BUt74oHgSj+vHepnhunn0JJAMtBZgDI/qmGtMujRv8DDpo47zBJ8UtPOuAR/7rKn8t9AJ0tBdmBAmJ/Fu71yxp4I3qh+DhyRqbi5Y1ShVPlSb8X7bRNcfgZFl+WRGYo7uecrWq1r8X5bhmzP5OdlDwsGRm1suSxkg5rYm7ConyGQ3Zl+DgSD8V/kPwrWBMG9YcBtyShBnTLdTiHgttw7qAW7cqh/ZnmPKr/6ignOaKsdyxbsToT5UkPsW00bJjijDXficcX/JsLs6w2BwGtherdckH3w/kNXRPVI0OqJQoHX42/66IMfMj/2huRjxIidgKV/W0JS+bsstDoTeAHcrI8E5zTh/sDkqxL5rZup55/3USlswfcHf4IrQplVDgW9XFlOqnwr6pVPMMEZTuC60EttvdzbLbaZ4PsFVa3nohhO+vW+yn/ZB2fUhpysmQrzBcTSai9EszuZMcEZ1lCFVrp9zGXhm69iLyY4oxFIa178lPe12I/P2DAYDAaDwWAwGAwGg8FgMBgMBoPBYDD2Cf8IMADDRGoQTe+E9AAAAABJRU5ErkJggg==' style='margin-top: -16px;' width='92'/> </a> <ul> <li> <a href='//www.google.com/'> Google </a> </li> <li> <a href='//www.google.com/policies/privacy/'> Privacy </a> </li> <li> <a href='//www.google.com/policies/terms/'> Terms </a> </li> </ul> </div> </div> <script type='text/javascript'> //<![CDATA[ // Social sharing popups. var postEl = document.getElementsByClassName('social-wrapper'); var postCount = postEl.length; for(i=0; i<postCount;i++){ postEl[i].addEventListener("click", function(event){ var postUrl = this.getAttribute("data-href"); window.open( postUrl,'popUpWindow','height=500,width=500,left=10,top=10,resizable=yes,scrollbars=yes,toolbar=yes,menubar=no,location=no,directories=no,status=yes'); });} //]]> </script> <script type='text/javascript'> //<![CDATA[ var BreakpointHandler = function() { this.initted = false; this.isHomePage = false; this.isMobile = false; }; BreakpointHandler.prototype.finalizeSummary = function(summaryHtml, lastNode) { // Use $.trim for IE8 compatibility summaryHtml = $.trim(summaryHtml).replace(/(<br>|\s)+$/,''); if (lastNode.nodeType == 3) { var lastChar = summaryHtml.slice(-1); if (!lastChar.match(/[.”"?]/)) { if (!lastChar.match(/[A-Za-z]/)) { summaryHtml = summaryHtml.slice(0, -1); } summaryHtml += ' ...'; } } else if (lastNode.nodeType == 1 && (lastNode.nodeName == 'I' || lastNode.nodeName == 'A')) { summaryHtml += ' ...'; } return summaryHtml; }; BreakpointHandler.prototype.generateSummaryFromContent = function(content, numWords) { var seenWords = 0; var summaryHtml = ''; for (var i=0; i < content.childNodes.length; i++) { var node = content.childNodes[i]; var nodeText; if (node.nodeType == 1) { if (node.hasAttribute('data-about-pullquote')) { continue; } nodeText = node.textContent; if (nodeText === undefined) { // innerText for IE8 nodeText = node.innerText; } if (node.nodeName == 'DIV' || node.nodeName == 'B') { // Don't end early if we haven't seen enough words. if (seenWords < 10) { continue; } if (i > 0) { summaryHtml = this.finalizeSummary(summaryHtml, content.childNodes[i-1]); } break; } summaryHtml += node.outerHTML; } else if (node.nodeType == 3) { nodeText = node.nodeValue; summaryHtml += nodeText + ' '; } var words = nodeText.match(/\S+\s*/g); if (!words) { continue; } var remain = numWords - seenWords; if (words.length >= remain) { summaryHtml = this.finalizeSummary(summaryHtml, node); break; } seenWords += words.length; } return summaryHtml; }; BreakpointHandler.prototype.detect = function() { var match, pl = /\+/g, search = /([^&=]+)=?([^&]*)/g, decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); }, query = window.location.search.substring(1); var urlParams = {}; while (match = search.exec(query)) urlParams[decode(match[1])] = decode(match[2]); this.isListPage = $('html').hasClass('list-page'); this.isMobile = urlParams['m'] === '1'; this.isHomePage = window.location.pathname == '/'; }; BreakpointHandler.prototype.initContent = function() { var self = this; $('.post').each(function(index) { var body = $(this).children('.post-body')[0]; var content = $(body).children('.post-content')[0]; $(content).addClass('post-original'); var data = $(content).children('script').html(); data = self.rewriteForSSL(data); // If exists, extract specified editor's preview. var match = data.match(/([\s\S]+?)<div data-is-preview.+?>([\s\S]+)<\/div>/m); if (match) { data = match[1]; } // Prevent big images from loading when they aren't needed. // This must be done as a pre-injection step, since image loading can't be // canceled once embedded into the DOM. if (self.isListPage && self.isMobile) { data = data.replace(/<(img|iframe) .+?>/g, ''); } // Insert template to be rendered as nodes. content.innerHTML = data; if (self.isListPage) { var summary = document.createElement('div'); $(summary).addClass('post-content'); $(summary).addClass('post-summary'); body.insertBefore(summary, content); if (match) { // Use provided summary. summary.innerHTML = match[2]; } else { // Generate a summary. // Summary generation relies on DOM, so it must occur after content is // inserted into the page. summary.innerHTML = self.generateSummaryFromContent(content, 30); } // Add read more link to summary. var titleAnchor = $(this).find('.title a')[0]; var link = titleAnchor.cloneNode(true); link.innerHTML = 'Read More'; $(link).addClass('read-more'); summary.appendChild(link); } }); // Firefox does not allow for proper styling of BR. if (navigator.userAgent.indexOf('Firefox') > -1) { $('.post-content br').replaceWith('<span class="space"></span>'); } $('.loading').removeClass('loading'); }; BreakpointHandler.prototype.process = function() { if (!this.initted) { var makeInsecureImageRegex = function(hosts) { var whitelist = hosts.join('|').replace(/\./g,'\\.'); // Normal image tags, plus input images (yes, this is possible!) return new RegExp('(<(img|input)[^>]+?src=("|\'))http:\/\/(' + whitelist +')', 'g'); }; this.sslImageRegex = makeInsecureImageRegex(BreakpointHandler.KNOWN_HTTPS_HOSTS); this.sslImageCurrentDomainRegex = makeInsecureImageRegex([window.location.hostname]); this.detect(); this.initContent(); this.initted = true; } }; BreakpointHandler.KNOWN_HTTPS_HOSTS = [ "www.google.org", "www.google.com", "services.google.com", "blogger.com", "draft.blogger.com", "www.blogger.com", "photos1.blogger.com", "photos2.blogger.com", "photos3.blogger.com", "blogblog.com", "img1.blogblog.com", "img2.blogblog.com", "www.blogblog.com", "www1.blogblog.com", "www2.blogblog.com", "0.bp.blogspot.com", "1.bp.blogspot.com", "2.bp.blogspot.com", "3.bp.blogspot.com", "4.bp.blogspot.com", "lh3.googleusercontent.com", "lh4.googleusercontent.com", "lh5.googleusercontent.com", "lh6.googleusercontent.com", "themes.googleusercontent.com", ]; BreakpointHandler.prototype.rewriteForSSL = function(html) { // Handle HTTP -> HTTPS source replacement of images, movies, and other embedded content. return html.replace(this.sslImageRegex, '$1https://$4') .replace(this.sslImageCurrentDomainRegex, '$1//$4') .replace(/(<(embed|iframe)[^>]+?src=("|'))http:\/\/([^"']*?(youtube|picasaweb\.google)\.com)/g, '$1https://$4') // Slideshow SWF takes a image host, so we need to rewrite that parameter. .replace(/(<embed[^>]+?feed=http(?=[^s]))/g, '$1s'); }; $(document).ready(function() { var handler = new BreakpointHandler(); handler.process(); // Top-level navigation. $(".BlogArchive .tab").click(function(ev) { ev.preventDefault(); $(this).parent().toggleClass('active'); $(this).siblings().slideToggle(300); }); $(".Label .tab").click(function(ev) { ev.preventDefault(); $(this).parent().toggleClass('active'); $(this).siblings().slideToggle(300); }); // Blog archive year expansion. $('.BlogArchive .intervalToggle').click(function(ev) { ev.preventDefault(); if ($(this).parent().hasClass('collapsed')) { $(this).parent().removeClass('collapsed'); $(this).parent().addClass('expanded'); } else { $(this).parent().removeClass('expanded'); $(this).parent().addClass('collapsed'); } }); // Reverse order of months. $('.BlogArchive .intervalToggle + div').each(function(_, items) { var year = $(this); year.children().each(function(_, month) { year.prepend(month); }); }); // Set anchors to open in new tab. $('.post-content img').parent().each(function(_, node) { if (node.nodeName == 'A') { $(this).attr('target', '_blank'); } }); // Process search requests. $('.searchBox input').on("keypress", function(ev) { if (ev.which == 13) { window.location.href = 'https://www.google.com/search?q=site%3A' + window.location.hostname + '%20' + encodeURIComponent ($(this).val()); } }); }); (function($, window) { var archiveButton = $($('#sidebar .widget.BlogArchive h2')[0]); var folderIcon = $('#sidebar .widget.BlogArchive h2::after'); var archivePanel = $('#BlogArchive1'); archiveButton.click(function(e) { if (archivePanel.hasClass('archive-open')) { // It's open, so now we close it archivePanel.removeClass('archive-open'); archivePanel.addClass('archive-closed'); archiveButton.removeClass('archive-open'); archiveButton.addClass('archive-closed'); archivePanel.css('height', '60px'); } else { // It's closed, so open it archivePanel.removeClass('archive-closed'); archivePanel.addClass('archive-open'); archiveButton.removeClass('archive-closed'); archiveButton.addClass('archive-open'); archivePanel.css('height', 'auto'); folderIcon.css('content', 'https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggkDzi8QVSua_XxLOnfxWE_8nQc1MAhRPBxJej91JW2ZBbKvb2TjaNf66ZoTqCrBivwRr-TLJYxFm2ZAiMd-zfbJ0TjblXGvUszWFbdRncNOL7jseiJCL9uQoqN8BM8FpesdSw/s1600/keyboard_arrow_up_grey600_24dp.png'); } }); })($, window); (function ($, window, devsite) { devsite.devsite = {}; devsite.expandLeftNav = devsite.expandLeftNav || {}; devsite.expandLeftNav.ANALYTICS_LABEL_ = 'Hamburger menu'; devsite.expandLeftNav.ANALYTICS_ACTION_OPEN_ = 'Open'; devsite.expandLeftNav.ANALYTICS_ACTION_CLOSE_ = 'Close'; devsite.expandLeftNav.lastState_ = 0; devsite.expandLeftNav.chekovEnabled_ = false; devsite.expandLeftNav.init = function () { devsite.expandLeftNav.chekovEnabled_ = true; var navElement; if (devsite.expandLeftNav.chekovEnabled_) { navElement = $('.devsite-nav-responsive'); } else { navElement = $('.devsite-section-nav-responsive'); } this.drawerWidth = parseInt(navElement.css('width')); navElement.css({ 'left': -(this.drawerWidth) }); var expandButton = $('.devsite-expand-section-nav'); expandButton.click(function () { devsite.expandLeftNav.handleNavigationOpened(); }); navElement.find('.devsite-nav-responsive-forward').click( devsite.expandLeftNav.openPanel); navElement.find('.devsite-nav-responsive-back').click( devsite.expandLeftNav.closePanel); if ($('.devsite-nav-responsive-tabs-panel + ' + '.devsite-nav-responsive-sidebar-panel').length) { devsite.expandLeftNav.openPanel(); } }; devsite.expandLeftNav.handleNavigationOpened = function (opt_noAnimate) { var mask; if (devsite.expandLeftNav.chekovEnabled_) { var nav = $('.devsite-nav-responsive'); if (opt_noAnimate) { nav.addClass('devsite-nav-responsive-no-animate'); mask = devsite.devsite.showSiteMask(0); } else { mask = devsite.devsite.showSiteMask(); } nav.addClass('devsite-nav-responsive-open'); } else { devsite.expandLeftNav.lastState_ = devsite.sticky.currentState; devsite.sticky.setState(devsite.sticky.state.COLLAPSED_HEADER); var headerHeight = devsite.sticky.getHeaderHeight() - devsite.sticky.desiredMargin; var drawerHeight = $(window).height() - headerHeight; mask = devsite.devsite.showArticleMask(); $('.devsite-section-nav-responsive').css({ 'height': drawerHeight, 'left': '0', 'top': headerHeight, 'visibility': 'visible' }).focus(); } $(mask).click(devsite.expandLeftNav.handleNavigationClosed); $(document).on('keydown.escape', function (e) { if (e.keyCode == $.ui.keyCode.ESCAPE) { devsite.expandLeftNav.handleNavigationClosed(); $(document).off('keydown.escape'); } }); }; devsite.expandLeftNav.getScrollTop = function () { return $(window).scrollTop(); }; devsite.expandLeftNav.handleNavigationClosed = function () { var nav; if (devsite.expandLeftNav.chekovEnabled_) { nav = $('.devsite-nav-responsive'); devsite.devsite.hideSiteMask(); nav.removeClass('devsite-nav-responsive-open ' + 'devsite-nav-responsive-no-animate'); } else { nav = $('.devsite-section-nav-responsive'); devsite.devsite.hideArticleMask(); devsite.sticky.setState(devsite.expandLeftNav.lastState_); nav .css('left', -(devsite.expandLeftNav.drawerWidth)) .one('transitionend', function () { nav.css('visibility', 'hidden'); }); } nav.scrollTop(0); }; devsite.expandLeftNav.openPanel = function () { var parentPanel = $('.devsite-nav-responsive-tabs-panel'); var childPanel = $('.devsite-nav-responsive-sidebar-panel'); childPanel.show(); parentPanel .addClass('devsite-nav-responsive-transition') .addClass('devsite-nav-responsive-transform') .one('transitionend', function () { childPanel .removeClass('devsite-nav-responsive-transition') .removeClass('devsite-nav-responsive-transform'); parentPanel.hide(); }); setTimeout(function () { childPanel .addClass('devsite-nav-responsive-transition') .addClass('devsite-nav-responsive-transform'); }, 1); }; devsite.expandLeftNav.closePanel = function () { var parentPanel = $('.devsite-nav-responsive-tabs-panel'); var childPanel = $('.devsite-nav-responsive-sidebar-panel'); childPanel .removeClass('devsite-nav-responsive-transition') .addClass('devsite-nav-responsive-transform'); parentPanel .show() .removeClass('devsite-nav-responsive-transition') .addClass('devsite-nav-responsive-transform'); setTimeout(function () { parentPanel .addClass('devsite-nav-responsive-transition') .removeClass('devsite-nav-responsive-transform'); childPanel .addClass('devsite-nav-responsive-transition') .removeClass('devsite-nav-responsive-transform') .one('transitionend', function () { childPanel.hide(); parentPanel.removeClass('devsite-nav-responsive-transition'); }); }, 1); }; devsite.expandLeftNav.FADE_SLOW_ = 'slow'; devsite.expandLeftNav.FADE_FAST_ = 'fast'; devsite.expandLeftNav.SITE_MASK_CSS_ = '.devsite-site-mask'; devsite.devsite.showSiteMask = function(opt_animate) { if (opt_animate === undefined) { opt_animate = devsite.expandLeftNav.FADE_SLOW_; } devsite.devsite.setMouseScrollingEnabled(false); return devsite.devsite.setMask_(devsite.expandLeftNav.SITE_MASK_CSS_, false, opt_animate); }; devsite.devsite.hideSiteMask = function(opt_animate) { if (opt_animate === undefined) { opt_animate = devsite.expandLeftNav.FADE_FAST_; } devsite.devsite.setMouseScrollingEnabled(true); return devsite.devsite.setMask_(devsite.expandLeftNav.SITE_MASK_CSS_, true, opt_animate); }; devsite.devsite.showArticleMask = function() { devsite.devsite.setMouseScrollingEnabled(false); return devsite.devsite.setMask_('.devsite-article-mask', false, devsite.expandLeftNav.FADE_SLOW_); }; devsite.devsite.hideArticleMask = function() { devsite.devsite.setMouseScrollingEnabled(true); return devsite.devsite.setMask_('.devsite-article-mask', true, devsite.expandLeftNav.FADE_FAST_); }; devsite.devsite.setMask_ = function(className, out, opt_fadeTime) { var query = $(className); if (opt_fadeTime === 0) { out ? query.hide() : query.show(); } else { out ? query.fadeOut(opt_fadeTime) : query.fadeIn(opt_fadeTime); } return $(className)[0]; }; devsite.devsite.setMouseScrollingEnabled = function(trueOrFalse) { if (trueOrFalse == true) { $('html, body').css({ 'overflow': '' }); } else { $('html, body').css({ 'overflow': 'hidden' }); } }; })($, window, devsite = {}); if (window.jQuery) { $(document).ready(function () { if (window.devsite) { devsite.expandLeftNav.init(); } }); } //]]> </script> <style> .widget ul{ line-height: 1.6 !important; } #sidebar ul li a{ color:black; line-height: 20px; } #sidebar ul li a:hover{ color:#4184F3; } </style> <script type="text/javascript" src="https://www.blogger.com/static/v1/widgets/60983134-widgets.js"></script> <script type='text/javascript'> window['__wavt'] = 'AOuZoY5ZNhR3k4MDLwSPTUiO4mwzMcwXPw:1739712736414';_WidgetManager._Init('//www.blogger.com/rearrange?blogID\x3d15045980','//testing.googleblog.com/2008/06/','15045980'); _WidgetManager._SetDataContext([{'name': 'blog', 'data': {'blogId': '15045980', 'title': 'Google Testing Blog', 'url': 'https://testing.googleblog.com/2008/06/', 'canonicalUrl': 'https://testing.googleblog.com/2008/06/', 'homepageUrl': 'https://testing.googleblog.com/', 'searchUrl': 'https://testing.googleblog.com/search', 'canonicalHomepageUrl': 'https://testing.googleblog.com/', 'blogspotFaviconUrl': 'https://testing.googleblog.com/favicon.ico', 'bloggerUrl': 'https://www.blogger.com', 'hasCustomDomain': true, 'httpsEnabled': true, 'enabledCommentProfileImages': true, 'gPlusViewType': 'FILTERED_POSTMOD', 'adultContent': false, 'analyticsAccountNumber': 'G-838ZCPQWM6', 'analytics4': true, 'encoding': 'UTF-8', 'locale': 'en', 'localeUnderscoreDelimited': 'en', 'languageDirection': 'ltr', 'isPrivate': false, 'isMobile': false, 'isMobileRequest': false, 'mobileClass': '', 'isPrivateBlog': false, 'isDynamicViewsAvailable': true, 'feedLinks': '\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Google Testing Blog - Atom\x22 href\x3d\x22https://testing.googleblog.com/feeds/posts/default\x22 /\x3e\n\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/rss+xml\x22 title\x3d\x22Google Testing Blog - RSS\x22 href\x3d\x22https://testing.googleblog.com/feeds/posts/default?alt\x3drss\x22 /\x3e\n\x3clink rel\x3d\x22service.post\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Google Testing Blog - Atom\x22 href\x3d\x22https://www.blogger.com/feeds/15045980/posts/default\x22 /\x3e\n', 'meTag': '', 'adsenseHostId': 'ca-host-pub-1556223355139109', 'adsenseHasAds': false, 'adsenseAutoAds': false, 'boqCommentIframeForm': true, 'loginRedirectParam': '', 'view': '', 'dynamicViewsCommentsSrc': '//www.blogblog.com/dynamicviews/4224c15c4e7c9321/js/comments.js', 'dynamicViewsScriptSrc': '//www.blogblog.com/dynamicviews/32c3d108bdd93523', 'plusOneApiSrc': 'https://apis.google.com/js/platform.js', 'disableGComments': true, 'interstitialAccepted': false, 'sharing': {'platforms': [{'name': 'Get link', 'key': 'link', 'shareMessage': 'Get link', 'target': ''}, {'name': 'Facebook', 'key': 'facebook', 'shareMessage': 'Share to Facebook', 'target': 'facebook'}, {'name': 'BlogThis!', 'key': 'blogThis', 'shareMessage': 'BlogThis!', 'target': 'blog'}, {'name': 'X', 'key': 'twitter', 'shareMessage': 'Share to X', 'target': 'twitter'}, {'name': 'Pinterest', 'key': 'pinterest', 'shareMessage': 'Share to Pinterest', 'target': 'pinterest'}, {'name': 'Email', 'key': 'email', 'shareMessage': 'Email', 'target': 'email'}], 'disableGooglePlus': true, 'googlePlusShareButtonWidth': 0, 'googlePlusBootstrap': '\x3cscript type\x3d\x22text/javascript\x22\x3ewindow.___gcfg \x3d {\x27lang\x27: \x27en\x27};\x3c/script\x3e'}, 'hasCustomJumpLinkMessage': false, 'jumpLinkMessage': 'Read more', 'pageType': 'archive', 'pageName': 'June 2008', 'pageTitle': 'Google Testing Blog: June 2008'}}, {'name': 'features', 'data': {}}, {'name': 'messages', 'data': {'edit': 'Edit', 'linkCopiedToClipboard': 'Link copied to clipboard!', 'ok': 'Ok', 'postLink': 'Post Link'}}, {'name': 'template', 'data': {'name': 'custom', 'localizedName': 'Custom', 'isResponsive': false, 'isAlternateRendering': false, 'isCustom': true}}, {'name': 'view', 'data': {'classic': {'name': 'classic', 'url': '?view\x3dclassic'}, 'flipcard': {'name': 'flipcard', 'url': '?view\x3dflipcard'}, 'magazine': {'name': 'magazine', 'url': '?view\x3dmagazine'}, 'mosaic': {'name': 'mosaic', 'url': '?view\x3dmosaic'}, 'sidebar': {'name': 'sidebar', 'url': '?view\x3dsidebar'}, 'snapshot': {'name': 'snapshot', 'url': '?view\x3dsnapshot'}, 'timeslide': {'name': 'timeslide', 'url': '?view\x3dtimeslide'}, 'isMobile': false, 'title': 'Google Testing Blog', 'description': '', 'url': 'https://testing.googleblog.com/2008/06/', 'type': 'feed', 'isSingleItem': false, 'isMultipleItems': true, 'isError': false, 'isPage': false, 'isPost': false, 'isHomepage': false, 'isArchive': true, 'isLabelSearch': false, 'archive': {'year': 2008, 'month': 6, 'rangeMessage': 'Showing posts from June, 2008'}}}]); _WidgetManager._RegisterWidget('_HeaderView', new _WidgetInfo('Header1', 'header', document.getElementById('Header1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogView', new _WidgetInfo('Blog1', 'main', document.getElementById('Blog1'), {'cmtInteractionsEnabled': false, 'lightboxEnabled': true, 'lightboxModuleUrl': 'https://www.blogger.com/static/v1/jsbin/918196653-lbx.js', 'lightboxCssUrl': 'https://www.blogger.com/static/v1/v-css/1964470060-lightbox_bundle.css'}, 'displayModeFull')); _WidgetManager._RegisterWidget('_HTMLView', new _WidgetInfo('HTML8', 'sidebar-top', document.getElementById('HTML8'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_LabelView', new _WidgetInfo('Label1', 'sidebar', document.getElementById('Label1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogArchiveView', new _WidgetInfo('BlogArchive1', 'sidebar', document.getElementById('BlogArchive1'), {'languageDirection': 'ltr', 'loadingMessage': 'Loading\x26hellip;'}, 'displayModeFull')); _WidgetManager._RegisterWidget('_HTMLView', new _WidgetInfo('HTML6', 'sidebar', document.getElementById('HTML6'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_HTMLView', new _WidgetInfo('HTML9', 'sidebar-bottom', document.getElementById('HTML9'), {}, 'displayModeFull')); </script> </body> </html>