CINXE.COM

Google Testing Blog: September 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: September 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/09/' 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/09/' 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/09/' 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&amp;zx=4804591f-4b0d-457d-91c1-fd6e244b873a' media='none' onload='if(media!=&#39;all&#39;)media=&#39;all&#39;' rel='stylesheet'/><noscript><link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=15045980&amp;zx=4804591f-4b0d-457d-91c1-fd6e244b873a' 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='992663051743495204' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://testing.googleblog.com/2008/09/by-miko-hevery-we-talked-about-how-it.html' itemprop='url' title=''> </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Friday, September 26, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <p> <br /> by <a href="http://misko.hevery.com/about/">Miško Hevery</a> <br /></p><p> <br /> We talked about how it is important to <a href="http://misko.hevery.com/2008/07/08/how-to-think-about-the-new-operator/">separate the new operators from the application logic</a>. This separation forces your code to have <a href="http://misko.hevery.com/2008/09/10/where-have-all-the-new-operators-gone/">factories which are responsible for wiring your application</a> together. By separating these responsibilities the tests can always wire together a subset of an application with key components replaced for friendlies making testing easier and more focused. <br /></p><p>Let's look at a sample factory <br /></p> <pre>class CarFactory { <br />Car create() { <br /> return new Car( <br /> new EngineCompartment( <br /> new Engine(), <br /><span style="font-family:Times;"><pre> new Door(new PowerWindow()), <br /> new Door(new PowerWindow()), <br /> new PowerSeat(), new PowerSeat()</pre></span> new ManualTransmission(), <br /> new PowerSteering(), <br /> new Battery() <br /> ), <br /> new Cabin( <br /> new Door(new PowerWindow()), <br /> new Door(new PowerWindow()), <br /> new PowerSeat(), new PowerSeat() <br /> ), <br /> Arrays.asList( <br /> new Wheel(new Tire(), new Rim()), <br /> new Wheel(new Tire(), new Rim()), <br /> new Wheel(new Tire(), new Rim()), <br /> new Wheel(new Tire(), new Rim()) <br /> ) <br /> ); <br />} <br />}</pre> This factory builds a car. The first thing to notice is that all of the <span style="font-family:Courier New;">new</span> operators are here (If you were to look inside each of the classes it would be devoid of "new"s). The second thing to notice is a complete lack of logic (no loops or conditions). And thirdly, your application behavior is controlled by the way the classes are wired together. If I wanted a automatic-transmission car, all I would have to do is to wire the classes differently. The wiring responsibility is in the factory class not with the application logic. <br /> <br />But why do we need to tell the JVM how to wire these Classes together? Is it not self obvious? Just look at the constructors of these classes: <br /><pre>Car(EngineCompartment ec, Cabin c, List<wheel> ws); <br />EngineCompartment(Engine e, Transmission t, <br /> Steering s, Battery b); <br />Cabin(Door driverDoor, Door passengerDoor, <br /> Seat driverSeat, Seat passengerSeat); <br />Engine(float dissplacement, int pistonCount); <br />Battery(float voltage); <br />Door(Window window); <br /><span style="font-family:Times;"><pre> new Door(new PowerWindow()), <br /> new Door(new PowerWindow()), <br /> new PowerSeat(), new PowerSeat()</pre></span>PowerWindow() implements Window; <br />PowerSeat() implements Seat; <br />Wheel(Tire tire, Rim rim); <br />...</wheel></pre><p> Imagine you could just ask for things. Lets start simple and look at the Wheel. The constructor of Wheel needs a Tire and Rim. So when we ask for a Wheel it should be obvious that we want <span style="font-family:Courier New;">new Wheel(new Tire(), new Rim())</span>. Why do we need to make this explicit in our factory? Lets build a framework from which we can ask for a class and it returns an instance of that class. So in our case if we ask for <span style="font-family:Courier New;">getInstance(Wheel.class)</span> it returns a <span style="font-family:Courier New;">new Wheel(new Tire(), new Rim())</span>. Now a framework like this is easy to build since all we need to do is look at the constructor and recursively try to instantiate the objects until all recursive constructors are satisfied. <br /></p><p>But things are a bit more complicated than that. What if we ask for Cabin, as in <span style="font-family:Courier New;">getInstance(Cabin.class)</span>? Well Cabin needs two Doors and two Seats, but Seat is an interface so we have to make a decision: What subclass of Seat should we instantiate? To help our framework make that decision, somewhere we will add a bind method such as <span style="font-family:Courier New;">bind(Seat.class, PowerSeat.class)</span>. Great! Now when we call <span style="font-family:Courier New;">getInstance(Seat.class)</span> the framework returns <span style="font-family:Courier New;">new PowerSeat()</span>. Similarly, we will have to call <span style="font-family:Courier New;">bind(Window.class, PowerWindow.class)</span>. Now we can call <span style="font-family:Courier New;">getInstance(Cabin.class)</span> and the framework will return <span style="font-family:Courier New;">new Cabin(new Door(new PowerWindow()), new Door(new PowerWindow()), new PowerSeat(), new PowerSeat())</span>. <br /></p><p>Notice that closer a class you ask for is to the root (Car in this case), the more work will the framework do for us. So ideally we just want to ask for the root object, Car. Calling getInstance(Car.class) will cause the framework to do all of the work originally in our factory. <br /></p><p>As you can see a framework which will call the new operators on your behalf is very useful. This is because you only have to ask for the root object (in our case the Car) and the framework will build the whole object graph on your behalf. This kinds of frameworks are called Automatic Dependency Injection frameworks and there are few of them our there. Namely <a href="http://code.google.com/p/google-guice/">GUICE</a>, <a href="http://www.picocontainer.org/">PicoContainer</a>, and <a href="http://www.springframework.org/">Spring</a>. <br /></p><p>Since I know most about <a href="http://code.google.com/p/google-guice/">GUICE</a>, The above example can be rewritten in GUICE like this: <br /></p> <pre>class CarModule extends AbstractModule() { <br />public void bind() { <br /> bind(Seat.class, PowerSeat.class); <br /> bind(Seat.class, PowerSeat.class); <br /> bind(Transmission.class, ManualTransmission.class); <br /> // maybe use a provider method?(jwolter) <br /> // maybe explain the need for different wheels, so use a Provider<wheel>; <br /> bind(new TypeLiteral<list><wheel>>(){}) <br /> .toProvider(new Provider<list><wheel>>(){ <br /> @Inject Provider<wheel> wp; <br /> List<wheel> get() { <br /> return Array.asList(wp.get(), wp.get(), <br /> wp.get(), wp.get()); <br /> } <br /> }); <br />} <br /> <br />// or, what I think is simpler and clearer <br />@Provides <br />List<wheel> provideWheels(Provider<wheel> wp) { <br /> return Array.asList(wp.get(), wp.get() <br /> wp.get(), wp.get()); <br />} <br />} <br />// Then somewhere create your application, using the injector only <br />// once, for the root object. <br />Injector injector = Guice.createInjector(new CarModule()); <br />Car car = injector.getInstance(Car.class);</wheel></wheel></wheel></wheel></wheel></list></wheel></list></wheel></pre>As you can see Automatic Dependency Injection frameworks can do a lot of things for you. Namely, that you don't have to worry about writing the factories. You simply declare dependencies, and write your application logic. As needed, you ask for your dependencies in a constructor and let the framework resolve all of them for you. You move the responsibility of calling the new operator to the framework. The DI-framework is your new "new". Now DI-frameworks can do lot of other things, which are beyond the scope of this article, such as manage object lifetimes, enforce singletons (in a good way, see: <a href="http://misko.hevery.com/2008/08/25/root-cause-of-singletons/">Root Cause of Singletons</a> and <a href="http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/">Singletons are Pathological Liars</a>) and manage different configurations of your application such as production vs development server. <br /> <br />For a more real life example of a Guice Module see: <a href="http://code.google.com/p/unit-test-teaching-examples/source/browse/trunk/src/di/webserver/CalculatorServerModule.java?r=6">CalculatorServerModule.java</a> <br /> <br />Also, the curious may wonder why a Provider<wheel> is injected into the provider method for List&lt;Wheel&gt;. This is because our 4 wheeled car needs to have different wheels. If we injected a single wheel, it would be assigned as the same wheel on all 4 positions. Providers, when used without any explicit scopes will return a new instance every time get() is called on them. <br /> <br /></wheel> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> <p> <br /> by <a href="http://misko.hevery.com/about/">Miško Hevery</a> <br /></p><p> <br /> We talked about how it is important to <a href="http://misko.hevery.com/2008/07/08/how-to-think-about-the-new-operator/">separate the new operators from the application logic</a>. This separation forces your code to have <a href="http://misko.hevery.com/2008/09/10/where-have-all-the-new-operators-gone/">factories which are responsible for wiring your application</a> together. By separating these responsibilities the tests can always wire together a subset of an application with key components replaced for friendlies making testing easier and more focused. <br /></p><p>Let's look at a sample factory <br /></p> <pre>class CarFactory { <br />Car create() { <br /> return new Car( <br /> new EngineCompartment( <br /> new Engine(), <br /><span style="font-family:Times;"><pre> new Door(new PowerWindow()), <br /> new Door(new PowerWindow()), <br /> new PowerSeat(), new PowerSeat()</pre></span> new ManualTransmission(), <br /> new PowerSteering(), <br /> new Battery() <br /> ), <br /> new Cabin( <br /> new Door(new PowerWindow()), <br /> new Door(new PowerWindow()), <br /> new PowerSeat(), new PowerSeat() <br /> ), <br /> Arrays.asList( <br /> new Wheel(new Tire(), new Rim()), <br /> new Wheel(new Tire(), new Rim()), <br /> new Wheel(new Tire(), new Rim()), <br /> new Wheel(new Tire(), new Rim()) <br /> ) <br /> ); <br />} <br />}</pre> This factory builds a car. The first thing to notice is that all of the <span style="font-family:Courier New;">new</span> operators are here (If you were to look inside each of the classes it would be devoid of "new"s). The second thing to notice is a complete lack of logic (no loops or conditions). And thirdly, your application behavior is controlled by the way the classes are wired together. If I wanted a automatic-transmission car, all I would have to do is to wire the classes differently. The wiring responsibility is in the factory class not with the application logic. <br /> <br />But why do we need to tell the JVM how to wire these Classes together? Is it not self obvious? Just look at the constructors of these classes: <br /><pre>Car(EngineCompartment ec, Cabin c, List<wheel> ws); <br />EngineCompartment(Engine e, Transmission t, <br /> Steering s, Battery b); <br />Cabin(Door driverDoor, Door passengerDoor, <br /> Seat driverSeat, Seat passengerSeat); <br />Engine(float dissplacement, int pistonCount); <br />Battery(float voltage); <br />Door(Window window); <br /><span style="font-family:Times;"><pre> new Door(new PowerWindow()), <br /> new Door(new PowerWindow()), <br /> new PowerSeat(), new PowerSeat()</pre></span>PowerWindow() implements Window; <br />PowerSeat() implements Seat; <br />Wheel(Tire tire, Rim rim); <br />...</wheel></pre><p> Imagine you could just ask for things. Lets start simple and look at the Wheel. The constructor of Wheel needs a Tire and Rim. So when we ask for a Wheel it should be obvious that we want <span style="font-family:Courier New;">new Wheel(new Tire(), new Rim())</span>. Why do we need to make this explicit in our factory? Lets build a framework from which we can ask for a class and it returns an instance of that class. So in our case if we ask for <span style="font-family:Courier New;">getInstance(Wheel.class)</span> it returns a <span style="font-family:Courier New;">new Wheel(new Tire(), new Rim())</span>. Now a framework like this is easy to build since all we need to do is look at the constructor and recursively try to instantiate the objects until all recursive constructors are satisfied. <br /></p><p>But things are a bit more complicated than that. What if we ask for Cabin, as in <span style="font-family:Courier New;">getInstance(Cabin.class)</span>? Well Cabin needs two Doors and two Seats, but Seat is an interface so we have to make a decision: What subclass of Seat should we instantiate? To help our framework make that decision, somewhere we will add a bind method such as <span style="font-family:Courier New;">bind(Seat.class, PowerSeat.class)</span>. Great! Now when we call <span style="font-family:Courier New;">getInstance(Seat.class)</span> the framework returns <span style="font-family:Courier New;">new PowerSeat()</span>. Similarly, we will have to call <span style="font-family:Courier New;">bind(Window.class, PowerWindow.class)</span>. Now we can call <span style="font-family:Courier New;">getInstance(Cabin.class)</span> and the framework will return <span style="font-family:Courier New;">new Cabin(new Door(new PowerWindow()), new Door(new PowerWindow()), new PowerSeat(), new PowerSeat())</span>. <br /></p><p>Notice that closer a class you ask for is to the root (Car in this case), the more work will the framework do for us. So ideally we just want to ask for the root object, Car. Calling getInstance(Car.class) will cause the framework to do all of the work originally in our factory. <br /></p><p>As you can see a framework which will call the new operators on your behalf is very useful. This is because you only have to ask for the root object (in our case the Car) and the framework will build the whole object graph on your behalf. This kinds of frameworks are called Automatic Dependency Injection frameworks and there are few of them our there. Namely <a href="http://code.google.com/p/google-guice/">GUICE</a>, <a href="http://www.picocontainer.org/">PicoContainer</a>, and <a href="http://www.springframework.org/">Spring</a>. <br /></p><p>Since I know most about <a href="http://code.google.com/p/google-guice/">GUICE</a>, The above example can be rewritten in GUICE like this: <br /></p> <pre>class CarModule extends AbstractModule() { <br />public void bind() { <br /> bind(Seat.class, PowerSeat.class); <br /> bind(Seat.class, PowerSeat.class); <br /> bind(Transmission.class, ManualTransmission.class); <br /> // maybe use a provider method?(jwolter) <br /> // maybe explain the need for different wheels, so use a Provider<wheel>; <br /> bind(new TypeLiteral<list><wheel>>(){}) <br /> .toProvider(new Provider<list><wheel>>(){ <br /> @Inject Provider<wheel> wp; <br /> List<wheel> get() { <br /> return Array.asList(wp.get(), wp.get(), <br /> wp.get(), wp.get()); <br /> } <br /> }); <br />} <br /> <br />// or, what I think is simpler and clearer <br />@Provides <br />List<wheel> provideWheels(Provider<wheel> wp) { <br /> return Array.asList(wp.get(), wp.get() <br /> wp.get(), wp.get()); <br />} <br />} <br />// Then somewhere create your application, using the injector only <br />// once, for the root object. <br />Injector injector = Guice.createInjector(new CarModule()); <br />Car car = injector.getInstance(Car.class);</wheel></wheel></wheel></wheel></wheel></list></wheel></list></wheel></pre>As you can see Automatic Dependency Injection frameworks can do a lot of things for you. Namely, that you don't have to worry about writing the factories. You simply declare dependencies, and write your application logic. As needed, you ask for your dependencies in a constructor and let the framework resolve all of them for you. You move the responsibility of calling the new operator to the framework. The DI-framework is your new "new". Now DI-frameworks can do lot of other things, which are beyond the scope of this article, such as manage object lifetimes, enforce singletons (in a good way, see: <a href="http://misko.hevery.com/2008/08/25/root-cause-of-singletons/">Root Cause of Singletons</a> and <a href="http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/">Singletons are Pathological Liars</a>) and manage different configurations of your application such as production vs development server. <br /> <br />For a more real life example of a Guice Module see: <a href="http://code.google.com/p/unit-test-teaching-examples/source/browse/trunk/src/di/webserver/CalculatorServerModule.java?r=6">CalculatorServerModule.java</a> <br /> <br />Also, the curious may wonder why a Provider<wheel> is injected into the provider method for List&lt;Wheel&gt;. This is because our 4 wheeled car needs to have different wheels. If we injected a single wheel, it would be assigned as the same wheel on all 4 positions. Providers, when used without any explicit scopes will return a new instance every time get() is called on them. <br /> <br /></wheel> <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:&url=https://testing.googleblog.com/2008/09/by-miko-hevery-we-talked-about-how-it.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/09/by-miko-hevery-we-talked-about-how-it.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'> &#57529; </i> <a href='https://testing.googleblog.com/2008/09/by-miko-hevery-we-talked-about-how-it.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/09/by-miko-hevery-we-talked-about-how-it.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/Misko%20Hevery' rel='tag'> Misko Hevery </a> </span> </div> </div> </div> <div class='post' data-id='9004881427552468679' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://testing.googleblog.com/2008/09/tott-mockin-ur-objectz.html' itemprop='url' title='TotT: Mockin Ur Objectz'> TotT: Mockin Ur Objectz </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Thursday, September 18, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <span style="font-style:italic;">[A light hearted episode this week... but still with a serious message. Enjoy. -Dave]</span><br /><br />HALP! Mah unit tests be doin' too much I/O! Testin' this lil' codes uses MOAR RESOURCES!<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%;">GIMME lol_io LIKE LOLIO</span><br /><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">SO IM LIKE PROCESSIN WIT DATAZ OK?</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;GIMME EACH BUCKET IN UR DATAZ OK?</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;&nbsp;&nbsp;BUCKET OWN FUBARRED?</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;N CAN HAS NONE</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;&nbsp;&nbsp;NOPE?</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;N CAN HAS 1</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;KTHXBYE N</span><br /><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">IZ __name__ KINDA LIKE &#8220;__main__&#8221;?</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;UR PROCESSIN WIT LOLIO OWN GET_SOME_DATAZ</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;BTW, GET_SOME_DATAZ USES UR INTERNETS LOL</span><br /></p><br />Oh NOES! Usin' internets in ur unit testz? Don't clog the tubes! Is not big truck! Mock the LOLIO thingy. No moar tubes!<br /><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%;">GIMME mock_lol_io LIKE LOLIO</span><br /> <br /><span style=" ;font-family:courier new, monospace;font-size:100%;">BTW, GIMME THING TO TEST</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">BTW, TEST THE THING NOW KTHX</span><br /></p><br />Now ur test runs fast! You can use mock_lol_io for killin' nondeterminism, too like for exceptions n stuff. Is fun, makes ur code execute pathz it nevar seen b4. Wit dis, you can see wut happens when theres a OH NOES like the tubez bein clogged.<br /><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%;">BTW, SOMETIMES THEY BE CALLIN DIS DEPENDENCY INJECTION ROFL</span><br /><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">BTW, YOU CAN UZE MOCKZ N STUF FER DIS LOOK:</span><br /><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">IN MAI library GIMME mock_filesystem LIKE LOL_FAKE_FILEYSTEM</span><br /><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">BTW, NOW U CAN USE LOL_FAKE_FILESYSTEM TO MAKE FAKE FILEZ IN MEMORY N STUFF</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">BTW, IS FASTER THAN OPENIN FILEZ ON TEST SERVAR</span><br /> </p><br />Now U know the sekrit for faster tests. Shh, don't tell Microsawft or the Yahew. They might be in our base, stealin our tech!<br /><br />KTHXBYE!<br /><br />Remember to download <a href="http://code.google.com/testing/TotT-2008-09-18.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> <span style="font-style:italic;">[A light hearted episode this week... but still with a serious message. Enjoy. -Dave]</span><br /><br />HALP! Mah unit tests be doin' too much I/O! Testin' this lil' codes uses MOAR RESOURCES!<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%;">GIMME lol_io LIKE LOLIO</span><br /><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">SO IM LIKE PROCESSIN WIT DATAZ OK?</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;GIMME EACH BUCKET IN UR DATAZ OK?</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;&nbsp;&nbsp;BUCKET OWN FUBARRED?</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;N CAN HAS NONE</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;&nbsp;&nbsp;NOPE?</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;N CAN HAS 1</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;KTHXBYE N</span><br /><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">IZ __name__ KINDA LIKE &#8220;__main__&#8221;?</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;UR PROCESSIN WIT LOLIO OWN GET_SOME_DATAZ</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;BTW, GET_SOME_DATAZ USES UR INTERNETS LOL</span><br /></p><br />Oh NOES! Usin' internets in ur unit testz? Don't clog the tubes! Is not big truck! Mock the LOLIO thingy. No moar tubes!<br /><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%;">GIMME mock_lol_io LIKE LOLIO</span><br /> <br /><span style=" ;font-family:courier new, monospace;font-size:100%;">BTW, GIMME THING TO TEST</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">BTW, TEST THE THING NOW KTHX</span><br /></p><br />Now ur test runs fast! You can use mock_lol_io for killin' nondeterminism, too like for exceptions n stuff. Is fun, makes ur code execute pathz it nevar seen b4. Wit dis, you can see wut happens when theres a OH NOES like the tubez bein clogged.<br /><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%;">BTW, SOMETIMES THEY BE CALLIN DIS DEPENDENCY INJECTION ROFL</span><br /><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">BTW, YOU CAN UZE MOCKZ N STUF FER DIS LOOK:</span><br /><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">IN MAI library GIMME mock_filesystem LIKE LOL_FAKE_FILEYSTEM</span><br /><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">BTW, NOW U CAN USE LOL_FAKE_FILESYSTEM TO MAKE FAKE FILEZ IN MEMORY N STUFF</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">BTW, IS FASTER THAN OPENIN FILEZ ON TEST SERVAR</span><br /> </p><br />Now U know the sekrit for faster tests. Shh, don't tell Microsawft or the Yahew. They might be in our base, stealin our tech!<br /><br />KTHXBYE!<br /><br />Remember to download <a href="http://code.google.com/testing/TotT-2008-09-18.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: Mockin Ur Objectz&url=https://testing.googleblog.com/2008/09/tott-mockin-ur-objectz.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/09/tott-mockin-ur-objectz.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'> &#57529; </i> <a href='https://testing.googleblog.com/2008/09/tott-mockin-ur-objectz.html#comments' style='font-weight: 500; text-decoration: underline;'>7 comments</a> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://testing.googleblog.com/2008/09/tott-mockin-ur-objectz.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='2525775816586687475' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://testing.googleblog.com/2008/09/presubmit-and-performance.html' itemprop='url' title='Presubmit And Performance'> Presubmit And Performance </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Thursday, September 18, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> Posted by Marc Kaplan, Test Engineering Manager<br /><br /><span class="Apple-style-span" style="border-collapse: collapse; color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;font-family:arial;font-size:100%;">When looking at whether to check a new change in, there are several testing-related questions that can be asked, which at least include:<br />1. Does the new functionality work?<br />2. Did this change break existing functionality?<br />3. What is the performance impact of this change?<br /><br />We can either answer these questions before we check things in, or after. We found that we can save a lot of time and effort in trying to do detective work and track bad changes down if we do this before check in to the depot. In most teams developers kick off the tests before they check anything in, but in case somebody forgets, or doesn't run all of the relevant tests, a more automated system was desired. So we have what we call<span class="Apple-converted-space"> </span><i>presubmit systems</i><span class="Apple-converted-space"> </span>at Google to run all of the relevant tests in an automated fashion pre-checkin, without the developer doing anything<span class="Apple-converted-space"> </span><i>before</i><span class="Apple-converted-space"> </span>the code is actually checked in. The idea behind this is that once the code is finished being written there are minutes or hours before it's checked in while it's being reviewed via the Google code review process (more info on that at<span class="Apple-converted-space"> </span><a href="//www.google.com/url?sa=t&amp;source=web&amp;ct=res&amp;cd=3&amp;url=http://video.google.com/videoplay?docid%3D-8502904076440714866&amp;ei=fazSSMrGLonYsAOS-fzuBw&amp;usg=AFQjCNEp_CaSowONUfpU9pC6vO1vArLBWg&amp;sig2=h9qTXoOjA1d-U82ZWK19Yw" target="_blank" style="color: rgb(42, 93, 176);">Guido's Tech Talk on Mondrian</a>). So we have taken advantage of this time by running tests via the presubmit system that finds all of the tests that are relevant to the change, runs the tests, and reports the results.<span class="Apple-converted-space"> </span><br /><br />Most of the work around presubmit at Google has been looking at functionality (question 1, and 2 above), however in the GFS Team where we are making a lot of performance-related changes we wondered whether a performance presubmit system would be possible. So recently we developed such a system and have begun to start using it. Basically a hook was added to the code review process such that once a developer sends out a change for review, and automated performance test is started via the<span class="Apple-converted-space"> </span><a href="http://googletesting.blogspot.com/2008/05/performance-testing-of-distributed-file.html" target="_blank" style="color: rgb(42, 93, 176);">GFS Performance Testing Tool</a><span class="Apple-converted-space"> </span>that we previously described on another Testing Blog post. Once two runs of the performance test are finished, they are compared against a known-good baseline that gets automatically created at the beginning of each week, and a comparison graph is generated and e-mailed to the user submitting the CL. So now we know, prior to checking some code in if it has some unexpected hit to performance. Additionally, now when a developer wants to make a change they think will improve performance they don't need to do anything other than a normal code review which will trigger an automatic performance test to see if they got the performance bump they were hoping for.<br /><br />Example of a performance presubmit report:<br /></span><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgj1Y1YpBcYTON9mCq4_gA5CGC9lvsdtZcQPMwOx77vC10ochylEH01TFX-4sgNWB_axpVXQzcQfGCD3JuUOBhiGMPRGMKd7y8OufQmTm1jSRKLy2stshDF_Z3f3t6wVkhn2b8v/s1600-h/statfs_Throughput.png"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5247497604416529186" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgj1Y1YpBcYTON9mCq4_gA5CGC9lvsdtZcQPMwOx77vC10ochylEH01TFX-4sgNWB_axpVXQzcQfGCD3JuUOBhiGMPRGMKd7y8OufQmTm1jSRKLy2stshDF_Z3f3t6wVkhn2b8v/s400/statfs_Throughput.png" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" /></a><br /><span class="Apple-style-span" style="border-collapse: collapse; color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;font-family:arial;font-size:100%;">I've seen many companies and projects where performance testing is cumbersome and not run very often until near release date. As you might expect, this is very problematic because once you find a performance bug you have to go back through all of the changes and try to narrow it down, and many times it's simply not that easy. Doing the performance testing early, and often helps narrow things down, but we've found that it's even better to make sure that these performance regressions never creep into the code with pre-check in performance testing. Certainly you should still do a final performance test once this code is frozen, but with the presubmit performance testing system in place you are essentially certain that the performance will be as good as you expect it to be.</span> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> Posted by Marc Kaplan, Test Engineering Manager<br /><br /><span class="Apple-style-span" style="border-collapse: collapse; color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;font-family:arial;font-size:100%;">When looking at whether to check a new change in, there are several testing-related questions that can be asked, which at least include:<br />1. Does the new functionality work?<br />2. Did this change break existing functionality?<br />3. What is the performance impact of this change?<br /><br />We can either answer these questions before we check things in, or after. We found that we can save a lot of time and effort in trying to do detective work and track bad changes down if we do this before check in to the depot. In most teams developers kick off the tests before they check anything in, but in case somebody forgets, or doesn't run all of the relevant tests, a more automated system was desired. So we have what we call<span class="Apple-converted-space"> </span><i>presubmit systems</i><span class="Apple-converted-space"> </span>at Google to run all of the relevant tests in an automated fashion pre-checkin, without the developer doing anything<span class="Apple-converted-space"> </span><i>before</i><span class="Apple-converted-space"> </span>the code is actually checked in. The idea behind this is that once the code is finished being written there are minutes or hours before it's checked in while it's being reviewed via the Google code review process (more info on that at<span class="Apple-converted-space"> </span><a href="//www.google.com/url?sa=t&amp;source=web&amp;ct=res&amp;cd=3&amp;url=http://video.google.com/videoplay?docid%3D-8502904076440714866&amp;ei=fazSSMrGLonYsAOS-fzuBw&amp;usg=AFQjCNEp_CaSowONUfpU9pC6vO1vArLBWg&amp;sig2=h9qTXoOjA1d-U82ZWK19Yw" target="_blank" style="color: rgb(42, 93, 176);">Guido's Tech Talk on Mondrian</a>). So we have taken advantage of this time by running tests via the presubmit system that finds all of the tests that are relevant to the change, runs the tests, and reports the results.<span class="Apple-converted-space"> </span><br /><br />Most of the work around presubmit at Google has been looking at functionality (question 1, and 2 above), however in the GFS Team where we are making a lot of performance-related changes we wondered whether a performance presubmit system would be possible. So recently we developed such a system and have begun to start using it. Basically a hook was added to the code review process such that once a developer sends out a change for review, and automated performance test is started via the<span class="Apple-converted-space"> </span><a href="http://googletesting.blogspot.com/2008/05/performance-testing-of-distributed-file.html" target="_blank" style="color: rgb(42, 93, 176);">GFS Performance Testing Tool</a><span class="Apple-converted-space"> </span>that we previously described on another Testing Blog post. Once two runs of the performance test are finished, they are compared against a known-good baseline that gets automatically created at the beginning of each week, and a comparison graph is generated and e-mailed to the user submitting the CL. So now we know, prior to checking some code in if it has some unexpected hit to performance. Additionally, now when a developer wants to make a change they think will improve performance they don't need to do anything other than a normal code review which will trigger an automatic performance test to see if they got the performance bump they were hoping for.<br /><br />Example of a performance presubmit report:<br /></span><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgj1Y1YpBcYTON9mCq4_gA5CGC9lvsdtZcQPMwOx77vC10ochylEH01TFX-4sgNWB_axpVXQzcQfGCD3JuUOBhiGMPRGMKd7y8OufQmTm1jSRKLy2stshDF_Z3f3t6wVkhn2b8v/s1600-h/statfs_Throughput.png"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5247497604416529186" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgj1Y1YpBcYTON9mCq4_gA5CGC9lvsdtZcQPMwOx77vC10ochylEH01TFX-4sgNWB_axpVXQzcQfGCD3JuUOBhiGMPRGMKd7y8OufQmTm1jSRKLy2stshDF_Z3f3t6wVkhn2b8v/s400/statfs_Throughput.png" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" /></a><br /><span class="Apple-style-span" style="border-collapse: collapse; color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;font-family:arial;font-size:100%;">I've seen many companies and projects where performance testing is cumbersome and not run very often until near release date. As you might expect, this is very problematic because once you find a performance bug you have to go back through all of the changes and try to narrow it down, and many times it's simply not that easy. Doing the performance testing early, and often helps narrow things down, but we've found that it's even better to make sure that these performance regressions never creep into the code with pre-check in performance testing. Certainly you should still do a final performance test once this code is frozen, but with the presubmit performance testing system in place you are essentially certain that the performance will be as good as you expect it to be.</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:Presubmit And Performance&url=https://testing.googleblog.com/2008/09/presubmit-and-performance.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/09/presubmit-and-performance.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'> &#57529; </i> <a href='https://testing.googleblog.com/2008/09/presubmit-and-performance.html#comments' style='font-weight: 500; text-decoration: underline;'>7 comments</a> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://testing.googleblog.com/2008/09/presubmit-and-performance.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/Marc%20Kaplan' rel='tag'> Marc Kaplan </a> </span> </div> </div> </div> <div class='post' data-id='1597407821578015431' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://testing.googleblog.com/2008/09/google-maps-api-open-sources-their.html' itemprop='url' title='The Google Maps API Open Source Their Selenium Test Suite'> The Google Maps API Open Source Their Selenium Test Suite </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Wednesday, September 17, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> The Google Maps API is one of our most popular developer products here at Google, and is also one of the trickiest to test because of its visual nature and diverse uses. It has to go through the standard backend and JsUnit testing, but then also through a suite of Selenium tests to make sure that DOM elements are positioned correctly, mouse events are triggered correctly, and even tests to address random bugs like <a href="http://code.google.com/p/gmaps-api-issues/issues/detail?id=517" target="_blank">Issue 517</a>, where IE errored out when an implicitly closed base tag was used in the developer's HTML. And to top it off, all those tests must pass in every one of the API's supported browsers.<br /><br />So, we decided to open source our selenium test suite so that developers could see the kind of integration tests we're currently running, and could even contribute their own tests that test specific functionality or an order of operations used on their site. What better way to make sure your site works with our API than contribute a test to make sure of it?<br /><br />You can read more about the suite on <a href="http://googlegeodevelopers.blogspot.com/2008/08/do-you-speak-selenese-contribute-to-our.html" target="_blank">our blog</a>, peruse through our tests, and if you're a Maps API developer yourself, send us a test or two! <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> The Google Maps API is one of our most popular developer products here at Google, and is also one of the trickiest to test because of its visual nature and diverse uses. It has to go through the standard backend and JsUnit testing, but then also through a suite of Selenium tests to make sure that DOM elements are positioned correctly, mouse events are triggered correctly, and even tests to address random bugs like <a href="http://code.google.com/p/gmaps-api-issues/issues/detail?id=517" target="_blank">Issue 517</a>, where IE errored out when an implicitly closed base tag was used in the developer's HTML. And to top it off, all those tests must pass in every one of the API's supported browsers.<br /><br />So, we decided to open source our selenium test suite so that developers could see the kind of integration tests we're currently running, and could even contribute their own tests that test specific functionality or an order of operations used on their site. What better way to make sure your site works with our API than contribute a test to make sure of it?<br /><br />You can read more about the suite on <a href="http://googlegeodevelopers.blogspot.com/2008/08/do-you-speak-selenese-contribute-to-our.html" target="_blank">our blog</a>, peruse through our tests, and if you're a Maps API developer yourself, send us a test or two! <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:The Google Maps API Open Source Their Selenium Test Suite&url=https://testing.googleblog.com/2008/09/google-maps-api-open-sources-their.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/09/google-maps-api-open-sources-their.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'> &#57529; </i> <a href='https://testing.googleblog.com/2008/09/google-maps-api-open-sources-their.html#comments' style='font-weight: 500; text-decoration: underline;'>5 comments</a> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://testing.googleblog.com/2008/09/google-maps-api-open-sources-their.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/APIs' rel='tag'> APIs </a> </span> </div> </div> </div> <div class='post' data-id='5787849677995901679' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://testing.googleblog.com/2008/09/where-have-all-new-operators-gone.html' itemprop='url' title='Where Have all the "new" Operators Gone?'> Where Have all the "new" Operators Gone? </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Thursday, September 11, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> By <a href="http://www.testabilityexplorer.org/about">Miško Hevery</a><br /><em>(the other title: Your Application has a Wiring Problem)</em><br /><br />In <a href="http://misko.hevery.com/2008/08/29/my-main-method-is-better-than-yours/">My main() Method Is Better Than Yours</a> we looked into what a main() method should look like. There we introduced a clear separation between (1) the responsibility of constructing the object graph and (2) the responsibility of running the application. The reason that this separation is important was outlined in <a href="http://misko.hevery.com/2008/07/08/how-to-think-about-the-new-operator/">How to Think About the &#8220;new&#8221; Operator</a>. So let us look at where have all of the new operators gone...<br /><br />Before we go further I want you to visualize your application in your mind. Think of the components of your application as physical boxes which need to be wired together to work. The wires are the references one component has to another. In an ideal application you can change the behavior of the application just by wiring the components differently. For example instead of instantiating LDAPAuthenticator you instantiate KerberosAuthenticator and you wire the KerberosAuthenticator to appropriate components which need to know about Authenticator. That is the basic idea. By <a href="http://misko.hevery.com/2008/07/08/how-to-think-about-the-new-operator/">removing the new operators from the application logic</a> you have separated the responsibility of wiring the components from the application logic, and this is highly desirable. So now the problem becomes, where have all the new operators gone?<br /><br />First lets look at a manual wiring process. In the <a href="http://misko.hevery.com/2008/08/29/my-main-method-is-better-than-yours/">main() method</a> we asked the ServerFactory to build us a Server (in our case a <a href="http://www.mortbay.org/jetty/">Jetty</a> Web Server) Now, server needs to be wired together with servlets. The servlets, in turn, need to be wired with their services and so on. Notice that the factory bellow is full of "new" operators. We are new-ing the components and we are passing the references of one component to another to create the wiring. This is the instantiation and wiring activity I asked you to visualize above. (Full <a href="http://code.google.com/p/unit-test-teaching-examples/source/browse/trunk/src/di/webserver/ServerBuilder.java?r=6">source</a>):<br /><pre> public Server buildServer() {<br /> Server server = new Server();<br /><br /> SocketConnector socketConnector<br /> = new SocketConnector();<br /> socketConnector.setPort(8080);<br /> server.addConnector(socketConnector);<br /><br /> new ServletBuilder(server)<br /> .addServlet("/calc", new CalculatorServlet(<br /> new Calculator()))<br /> .addServlet("/time", new TimeServlet(<br /> new Provider() {<br /> public Date get() {<br /> return new Date();<br /> }<br /> }));<br /><br /> return server;<br />}</pre><br />When I first suggest to people that application logic should not instantiate its own dependencies, I get two common objections which are myths:<br /><ol><br /><li><em>"So now each class needs a factory, therefore I have twice as many classes!</em>" Heavens No! Notice how our ServerFactory acted as a factory for many different classes. Looking at it I counted 7 or so classes which we instantiated in order to wire up our application. So it is not true that we have one to one correspondence. In theory you only need one Factory per object lifetime. You need one factory for all long-lived objects (your singletons) and one for all request-lifetime objects and so on. Now in practice we further split those by related concepts. (But that is a discussion for a separate blog article.) The important thing to realize is that: yes, you will have few more classes, but it will be no where close to doubling your load.</li><br /><li><em>"If each object asks for its dependencies, than I will have to pass those dependencies through all of the callers. This will make it really hard to add new dependencies to the classes."</em> The myth here is that call-graph and instantiation-graph are one and the same. We looked into this myth in <a href="http://misko.hevery.com/2008/08/21/where-have-all-the-singletons-gone/">Where have all the Singletons Gone</a>. Notice that the Jetty server calls the TimeServlet which calls the Date. If the constructor of Date or TimeServlet all of a sudden needed a new argument it would not effect any of the callers. The only code which would have to change is factory class above. This is because we have isolated the instantiation/wiring problem into this factory class. So in reality this makes it easier to add dependencies not harder.</li><br /></ol><br />Now there are few important things to remember. Factories should have no logic! Just instantiation/wiring (so you will probably not have any conditionals or loops). I should be able to call the factory to create a server in a unit test without any access to the file-system, threads or any other expensive CPU or I/O operations. Factory creates the server, but does not run it. The other thing you want to keep in mind is that the wiring process is often controlled by the command line arguments. This makes is so that your application can behave differently depending what you pass in on a command line. The difference in behavior is not conditionals sprinkled throughout your code-base but rather a different way of wiring your application up.<br /><br />Finally, here are few thoughts on my love/hate of Singletons (mentioned <a href="http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/">here</a> and <a href="http://misko.hevery.com/2008/08/25/root-cause-of-singletons/">here</a>) First a little review of singletons. A singleton with a lower case 's' is a good singleton and simply means a single instance of some class. A Singleton with an upper case 'S' is a design pattern which is a singleton (one instance of some class) with a global "instance" variable which makes it accessible from anywhere. It is the global instance variable which makes it globally accessible , which turns a singleton into a Singleton. So singleton is acceptable, and sometimes very helpful for a design, but Singleton relies on mutable global state, which inhibits testability and makes a brittle, hard to test design. Now notice that our factory created a whole bunch of singletons as in a single instance of something . Also notice how those singletons got explicitly passed into the services that needed them. So if you need a singleton you simply create a single instance of it in the factory and than pass that instance into all of the components which need them. There is no need for the global variable.<br /><br />For example a common use of Singleton is for a DB connection pool. In our example you would simply instantiate a new DBConnectionPool class in the top-most factory (above) which is responsible for creating the long-lived objects. Now lets say that both CalculatorServlet and TimeServlet would need a connection pool. In that case we would simply pass the same instance of the DBConnectionPool into each of the places where it is needed. Notice we have a singleton (DBConnectionPool) but we don't have any global variables associated with that singleton.<br /><pre> public Server buildServer() {<br /> Server server = new Server();<br /><br /> SocketConnector socketConnector<br /> = new SocketConnector();<br /> socketConnector.setPort(8080);<br /> server.addConnector(socketConnector);<br /><br /> <strong>DBConnectionPool pool = new DBConnectionPool();</strong><br /> new ServletBuilder(server)<br /> .addServlet("/calc", new CalculatorServlet(<br /> <strong>pool</strong>,<br /> new Calculator()))<br /> .addServlet("/time", new TimeServlet(<br /> <strong>pool</strong>,<br /> new Provider() {<br /> public Date get() {<br /> return new Date();<br /> }<br /> }));<br /><br /> return server;<br />}</pre> <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> By <a href="http://www.testabilityexplorer.org/about">Miško Hevery</a><br /><em>(the other title: Your Application has a Wiring Problem)</em><br /><br />In <a href="http://misko.hevery.com/2008/08/29/my-main-method-is-better-than-yours/">My main() Method Is Better Than Yours</a> we looked into what a main() method should look like. There we introduced a clear separation between (1) the responsibility of constructing the object graph and (2) the responsibility of running the application. The reason that this separation is important was outlined in <a href="http://misko.hevery.com/2008/07/08/how-to-think-about-the-new-operator/">How to Think About the &#8220;new&#8221; Operator</a>. So let us look at where have all of the new operators gone...<br /><br />Before we go further I want you to visualize your application in your mind. Think of the components of your application as physical boxes which need to be wired together to work. The wires are the references one component has to another. In an ideal application you can change the behavior of the application just by wiring the components differently. For example instead of instantiating LDAPAuthenticator you instantiate KerberosAuthenticator and you wire the KerberosAuthenticator to appropriate components which need to know about Authenticator. That is the basic idea. By <a href="http://misko.hevery.com/2008/07/08/how-to-think-about-the-new-operator/">removing the new operators from the application logic</a> you have separated the responsibility of wiring the components from the application logic, and this is highly desirable. So now the problem becomes, where have all the new operators gone?<br /><br />First lets look at a manual wiring process. In the <a href="http://misko.hevery.com/2008/08/29/my-main-method-is-better-than-yours/">main() method</a> we asked the ServerFactory to build us a Server (in our case a <a href="http://www.mortbay.org/jetty/">Jetty</a> Web Server) Now, server needs to be wired together with servlets. The servlets, in turn, need to be wired with their services and so on. Notice that the factory bellow is full of "new" operators. We are new-ing the components and we are passing the references of one component to another to create the wiring. This is the instantiation and wiring activity I asked you to visualize above. (Full <a href="http://code.google.com/p/unit-test-teaching-examples/source/browse/trunk/src/di/webserver/ServerBuilder.java?r=6">source</a>):<br /><pre> public Server buildServer() {<br /> Server server = new Server();<br /><br /> SocketConnector socketConnector<br /> = new SocketConnector();<br /> socketConnector.setPort(8080);<br /> server.addConnector(socketConnector);<br /><br /> new ServletBuilder(server)<br /> .addServlet("/calc", new CalculatorServlet(<br /> new Calculator()))<br /> .addServlet("/time", new TimeServlet(<br /> new Provider() {<br /> public Date get() {<br /> return new Date();<br /> }<br /> }));<br /><br /> return server;<br />}</pre><br />When I first suggest to people that application logic should not instantiate its own dependencies, I get two common objections which are myths:<br /><ol><br /><li><em>"So now each class needs a factory, therefore I have twice as many classes!</em>" Heavens No! Notice how our ServerFactory acted as a factory for many different classes. Looking at it I counted 7 or so classes which we instantiated in order to wire up our application. So it is not true that we have one to one correspondence. In theory you only need one Factory per object lifetime. You need one factory for all long-lived objects (your singletons) and one for all request-lifetime objects and so on. Now in practice we further split those by related concepts. (But that is a discussion for a separate blog article.) The important thing to realize is that: yes, you will have few more classes, but it will be no where close to doubling your load.</li><br /><li><em>"If each object asks for its dependencies, than I will have to pass those dependencies through all of the callers. This will make it really hard to add new dependencies to the classes."</em> The myth here is that call-graph and instantiation-graph are one and the same. We looked into this myth in <a href="http://misko.hevery.com/2008/08/21/where-have-all-the-singletons-gone/">Where have all the Singletons Gone</a>. Notice that the Jetty server calls the TimeServlet which calls the Date. If the constructor of Date or TimeServlet all of a sudden needed a new argument it would not effect any of the callers. The only code which would have to change is factory class above. This is because we have isolated the instantiation/wiring problem into this factory class. So in reality this makes it easier to add dependencies not harder.</li><br /></ol><br />Now there are few important things to remember. Factories should have no logic! Just instantiation/wiring (so you will probably not have any conditionals or loops). I should be able to call the factory to create a server in a unit test without any access to the file-system, threads or any other expensive CPU or I/O operations. Factory creates the server, but does not run it. The other thing you want to keep in mind is that the wiring process is often controlled by the command line arguments. This makes is so that your application can behave differently depending what you pass in on a command line. The difference in behavior is not conditionals sprinkled throughout your code-base but rather a different way of wiring your application up.<br /><br />Finally, here are few thoughts on my love/hate of Singletons (mentioned <a href="http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/">here</a> and <a href="http://misko.hevery.com/2008/08/25/root-cause-of-singletons/">here</a>) First a little review of singletons. A singleton with a lower case 's' is a good singleton and simply means a single instance of some class. A Singleton with an upper case 'S' is a design pattern which is a singleton (one instance of some class) with a global "instance" variable which makes it accessible from anywhere. It is the global instance variable which makes it globally accessible , which turns a singleton into a Singleton. So singleton is acceptable, and sometimes very helpful for a design, but Singleton relies on mutable global state, which inhibits testability and makes a brittle, hard to test design. Now notice that our factory created a whole bunch of singletons as in a single instance of something . Also notice how those singletons got explicitly passed into the services that needed them. So if you need a singleton you simply create a single instance of it in the factory and than pass that instance into all of the components which need them. There is no need for the global variable.<br /><br />For example a common use of Singleton is for a DB connection pool. In our example you would simply instantiate a new DBConnectionPool class in the top-most factory (above) which is responsible for creating the long-lived objects. Now lets say that both CalculatorServlet and TimeServlet would need a connection pool. In that case we would simply pass the same instance of the DBConnectionPool into each of the places where it is needed. Notice we have a singleton (DBConnectionPool) but we don't have any global variables associated with that singleton.<br /><pre> public Server buildServer() {<br /> Server server = new Server();<br /><br /> SocketConnector socketConnector<br /> = new SocketConnector();<br /> socketConnector.setPort(8080);<br /> server.addConnector(socketConnector);<br /><br /> <strong>DBConnectionPool pool = new DBConnectionPool();</strong><br /> new ServletBuilder(server)<br /> .addServlet("/calc", new CalculatorServlet(<br /> <strong>pool</strong>,<br /> new Calculator()))<br /> .addServlet("/time", new TimeServlet(<br /> <strong>pool</strong>,<br /> new Provider() {<br /> public Date get() {<br /> return new Date();<br /> }<br /> }));<br /><br /> return server;<br />}</pre> <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:Where Have all the "new" Operators Gone?&url=https://testing.googleblog.com/2008/09/where-have-all-new-operators-gone.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/09/where-have-all-new-operators-gone.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'> &#57529; </i> <a href='https://testing.googleblog.com/2008/09/where-have-all-new-operators-gone.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/09/where-have-all-new-operators-gone.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/Misko%20Hevery' rel='tag'> Misko Hevery </a> </span> </div> </div> </div> <div class='post' data-id='5616620937874760541' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://testing.googleblog.com/2008/09/test-first-is-fun_08.html' itemprop='url' title='Test first is fun!'> Test first is fun! </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Monday, September 08, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> <span class="byline-author">Posted by Philip Zembrod</span><br /><br />So the Test-Driven-Development and Extreme-Programming people tell you you should write your tests even before you write the actual code. "Now this is taking things a bit too far," you might think. "To the extreme, even. Why would I want to do this?"<br /><br />In this post, I'll tell you my answer to this question. I now really do want to write my tests first...and here's why!<br /><br />After many years of writing code without using or writing unit tests, I took a colleague's advice and read Kent Beck's "Extreme Programming Explained." I picked "write tests first" as the first XP practice to try out in my daily coding.<br /><br />The practice is: <span style="font-weight:bold;">Write a failing test for each feature</span> you plan to implement. Run the test and see it fail. <span style="font-weight:bold;">Then implement the feature until the test succeeds.</span> Refactor now and begin again.<br /><br />Why write the test first? The obvious reason, I thought, was to make it more likely that tests will get written at all. But I heard the promise that this was not just a way to ensure tests aren't overlooked, but <span style="font-weight:bold;">a way to higher productivity</span>. I tried it, and found that <span style="font-weight:bold;">getting tests written was indeed one of the less important reasons to write tests first!</span><br /><br />Writing tests firsts <span style="font-weight:bold;">leads you to think about the interface first</span>. Of course, you do that anyway when you write the header file with the C++ class definition or when you write a Java interface before you implement any methods. However, writing a test lets you <span style="font-weight:bold;">focus on how the new interface will be <span style="font-style:italic;">used</span></span> before even writing the interface. You could call writing the interface the supply side and writing the test the demand side of the deal. Writing the test first, you set out with the customer's or user's view of the new class.<br /><br />Another way of seeing the same thing is to <span style="font-weight:bold;">regard the test as a coded specification</span>. In the test, you specify what service the new class or feature should provide, and you specify, by example, the syntax with which this service will be requested. In contrast to specifications written in natural language, a specification written into a test contains <span style="font-weight:bold;">a technical safeguard against growing stale: if it does, the test will probably fail</span>.<br /><br />These two aspects of unit tests are enough to make me feel excited about writing them first. <span style="font-weight:bold;">Tests are no longer a necessary chore, but the place and time where I start to design something new. </span>That's what I love to do. How soon can I get started writing my next test?<br /><br />But this is still not the best part: If I write a test first, run it to see it fail (often even fail to compile), and write the code to satisfy the test, then I have everything in place to <span style="font-weight:bold;"><span style="font-style:italic;">see my code running the minute it is written and compiled!</span></span> No more dread of strange behaviour or system crashes the first time I launch the system with my new code! No more laborious navigating through the application to my code's feature! No more wondering: Did my code actually get executed or not?<br /><br />Just a quick run-the-testcase, and I know how my code runs: green - good. Red - not yet good. Read failure message and fix code until green. Debugging sucks, testing rocks, indeed!<br /><br />Of course, all the complex issues of integration and system testing remain. Good unit testing gives me a good head start for integration, but I might still be in for unpleasant surprises there.<br /><br />The point I want to make here, though, is about my state of mind when I write new code. For me, <span style="font-weight:bold;">writing new code for complex systems was always accompanied by fear</span>: fear of crashes I'd have to debug, fear of creating bugs I might not discover, fear of the dreary work of searching for bugs I might have created. Fear that took up a considerable amount of my mind space and <span style="font-weight:bold;">slowed me down</span>.<br /><br /><span style="font-weight:bold;">Now, this fear is gone!</span> I happily go about writing my code because I know the tests are already in place. <span style="font-weight:bold;">It will cost me just a few keystrokes to run my finished code, and I will immediately see what it does.</span> Hooray, I wrote a program, and it works, and it's easy to prove it!<br /><br /><span style="font-weight:bold;">It's the same old enthusiasm that I felt more than 20 years ago when I wrote and ran my first programs.</span> Many of you have felt it, too - the joy of inducing some life into this dead piece of hardware through our written word. And now this joy sits in my mind again where fear of crashes was before. You'd better believe that speeds up my coding! Want to give it a try yourself? <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">Posted by Philip Zembrod</span><br /><br />So the Test-Driven-Development and Extreme-Programming people tell you you should write your tests even before you write the actual code. "Now this is taking things a bit too far," you might think. "To the extreme, even. Why would I want to do this?"<br /><br />In this post, I'll tell you my answer to this question. I now really do want to write my tests first...and here's why!<br /><br />After many years of writing code without using or writing unit tests, I took a colleague's advice and read Kent Beck's "Extreme Programming Explained." I picked "write tests first" as the first XP practice to try out in my daily coding.<br /><br />The practice is: <span style="font-weight:bold;">Write a failing test for each feature</span> you plan to implement. Run the test and see it fail. <span style="font-weight:bold;">Then implement the feature until the test succeeds.</span> Refactor now and begin again.<br /><br />Why write the test first? The obvious reason, I thought, was to make it more likely that tests will get written at all. But I heard the promise that this was not just a way to ensure tests aren't overlooked, but <span style="font-weight:bold;">a way to higher productivity</span>. I tried it, and found that <span style="font-weight:bold;">getting tests written was indeed one of the less important reasons to write tests first!</span><br /><br />Writing tests firsts <span style="font-weight:bold;">leads you to think about the interface first</span>. Of course, you do that anyway when you write the header file with the C++ class definition or when you write a Java interface before you implement any methods. However, writing a test lets you <span style="font-weight:bold;">focus on how the new interface will be <span style="font-style:italic;">used</span></span> before even writing the interface. You could call writing the interface the supply side and writing the test the demand side of the deal. Writing the test first, you set out with the customer's or user's view of the new class.<br /><br />Another way of seeing the same thing is to <span style="font-weight:bold;">regard the test as a coded specification</span>. In the test, you specify what service the new class or feature should provide, and you specify, by example, the syntax with which this service will be requested. In contrast to specifications written in natural language, a specification written into a test contains <span style="font-weight:bold;">a technical safeguard against growing stale: if it does, the test will probably fail</span>.<br /><br />These two aspects of unit tests are enough to make me feel excited about writing them first. <span style="font-weight:bold;">Tests are no longer a necessary chore, but the place and time where I start to design something new. </span>That's what I love to do. How soon can I get started writing my next test?<br /><br />But this is still not the best part: If I write a test first, run it to see it fail (often even fail to compile), and write the code to satisfy the test, then I have everything in place to <span style="font-weight:bold;"><span style="font-style:italic;">see my code running the minute it is written and compiled!</span></span> No more dread of strange behaviour or system crashes the first time I launch the system with my new code! No more laborious navigating through the application to my code's feature! No more wondering: Did my code actually get executed or not?<br /><br />Just a quick run-the-testcase, and I know how my code runs: green - good. Red - not yet good. Read failure message and fix code until green. Debugging sucks, testing rocks, indeed!<br /><br />Of course, all the complex issues of integration and system testing remain. Good unit testing gives me a good head start for integration, but I might still be in for unpleasant surprises there.<br /><br />The point I want to make here, though, is about my state of mind when I write new code. For me, <span style="font-weight:bold;">writing new code for complex systems was always accompanied by fear</span>: fear of crashes I'd have to debug, fear of creating bugs I might not discover, fear of the dreary work of searching for bugs I might have created. Fear that took up a considerable amount of my mind space and <span style="font-weight:bold;">slowed me down</span>.<br /><br /><span style="font-weight:bold;">Now, this fear is gone!</span> I happily go about writing my code because I know the tests are already in place. <span style="font-weight:bold;">It will cost me just a few keystrokes to run my finished code, and I will immediately see what it does.</span> Hooray, I wrote a program, and it works, and it's easy to prove it!<br /><br /><span style="font-weight:bold;">It's the same old enthusiasm that I felt more than 20 years ago when I wrote and ran my first programs.</span> Many of you have felt it, too - the joy of inducing some life into this dead piece of hardware through our written word. And now this joy sits in my mind again where fear of crashes was before. You'd better believe that speeds up my coding! Want to give it a try yourself? <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 first is fun!&url=https://testing.googleblog.com/2008/09/test-first-is-fun_08.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/09/test-first-is-fun_08.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'> &#57529; </i> <a href='https://testing.googleblog.com/2008/09/test-first-is-fun_08.html#comments' style='font-weight: 500; text-decoration: underline;'>10 comments</a> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://testing.googleblog.com/2008/09/test-first-is-fun_08.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/Philip%20Zembrod' rel='tag'> Philip Zembrod </a> </span> </div> </div> </div> <div class='post' data-id='3359446571524205832' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://testing.googleblog.com/2008/09/my-main-method-is-better-than-yours.html' itemprop='url' title='My main() Method Is Better Than Yours'> My main() Method Is Better Than Yours </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Monday, September 08, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> By <a href="http://www.testabilityexplorer.org/about">Miško Hevery</a><br /><br />People are good at turning concrete examples into generalization. The other way around, it does not work so well. So when I write about general concepts it is hard for people to know how to translate the general concept into concrete code. To remedy this I will try to show few examples of how to build a web application from ground up. But I can't fit all of that into a single blog post ... So lets get started at the beginning...<br /><br />Here is what your main method should look like (no matter how complex your application) if you are using GUICE: (<a href="http://code.google.com/p/unit-test-teaching-examples/source/browse/trunk/src/di/webserver/GuiceDI.java">src</a>)<br /><pre>public static void main(String[] args)<br /> throws Exception {<br /> // Creation Phase<br /> Injector injector = Guice.createInjector(<br /> new CalculatorServerModule(args));<br /> Server server = injector.getInstance(Server.class);<br /> // Run Phase<br /> server.start();<br />}</pre><br />Or if you want to do manual dependency injection: (<a href="http://code.google.com/p/unit-test-teaching-examples/source/browse/trunk/src/di/webserver/ManualDI.java?r=6">src</a>)<br /><pre>public static void main(String[] args)<br /> throws Exception {<br /> // Creation Phase<br /> Server server = new ServerFactory(args)<br /> .createServer();<br /> // Run Phase<br /> server.start();<br />}</pre><br />The truth is I don't know how to test the main method. The main method is static and as a result there are no places where we can inject test-doubles. (I know we can fight static with static, but we already said that global state is bad <a href="http://misko.hevery.com/2008/08/25/root-cause-of-singletons/">here</a>, <a href="http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/">here</a> and <a href="http://misko.hevery.com/2008/07/24/how-to-write-3v1l-untestable-code/">here</a>). The reason we can't test this is that the moment you execute the main method the whole application runs, and that is not what we want and there is nothing we can do to prevent that.<br /><br />But the method is so short that I don't bother testing it since it has some really cool properties:<br /><ol><br /> <li>Notice how the creation-phase contains the code which builds the object graph of the application. The last line runs the application. The separation is very important. We can test the ServerFactory in isolation. Passing it different arguments and than asserting that the correct object graph got built. But, in order to do that the Factory class should do nothing but object graph construction. The object constructors better do nothing but field assignments. No reading of files, starting of threads, or any other work which would cause problems in unit-test. All we do is simply instantiate some graph of objects. The graph construction is controlled by the command line arguments which we passed into the constructor. So we can test creation-phase in isolation with unit-test. (Same applies for GUICE example)</li><br /> <li>The last line gets the application running. Here is where you can do all of your fun threads, file IO etc code. However, because the application is build from lots of objects collaborating together it is easy to test each object in isolation. In test I just instantiate the Server and pass in some test doubles in the constructor to mock out the not so interesting/hard to test code.</li><br /></ol><br />As you can see we have a clear separation of the object graph construction responsibility from the application logic code. If you were to examine the code in more detail you would find that all of the new operators have migrated from the run-phase to creation-phase (See <a href="http://misko.hevery.com/2008/07/08/how-to-think-about-the-new-operator/">How to Think About the &#8220;new&#8221; Operator</a>) And that is very important. New operator in application code is enemy of testing, but new in tests and factories is your friend. (The reason is that in tests we want to use test-doubles which are usually a subclass or an implementation of the parent class. If application code calls new than you can never replace that new with a subclass or different implementation.) The key is that the object creation responsibility and the the application code are two different responsibilities and they should not be mixed. Especially in the main method!<br /><br />A good way to think about this is that you want to design your application such that you can control the application behavior by controlling the way you wire the objects together (Object collaborator graph). Whether you wire in a InMemory, File or Database repository, PopServer or IMAPServer, LDAP or file based authentication. All these different behaviors should manifest themselves as different object graphs. The knowledge of how to wire the objects together should be stored in your factory class. If you want to prevent something from running in a test, you don't place an if statement in front of it. Instead you wire up a different graph of objects. You wire NullAthenticator in place of LDAPAuthenticator. Wiring your objects differently is how the tests determines what gets run and what gets mocked out. This is why it is important for the tests to have control of the new operators (or putting it differently the application code does not have the new operators). This is why we don't know how to test the main method. Main method is static and hence procedural. I don't know how to test procedural code since there is nothing to wire differently. I can't wire the call graph different in procedural world to prevent things from executing, the call graph is determined at compile time.<br /><br />In my experience that main method usually is some of the scariest code I have seen. Full of singleton initialization and threads. Completely untestable. What you want is that each object simply declares its dependencies in its constructor. (Here is the list of things I need to know about) Then when you start to write the Factory it will practically write itself. You simply try to new the object you need to return, which declares its dependencies, you in turn try to new those dependencies, etc... If there are some singletons you just have to make sure that you call the new operator only once. But more on factories in our next blog post... <span itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://plus.google.com/116899029375914044550' itemprop='url'/> </span> </script> <noscript> By <a href="http://www.testabilityexplorer.org/about">Miško Hevery</a><br /><br />People are good at turning concrete examples into generalization. The other way around, it does not work so well. So when I write about general concepts it is hard for people to know how to translate the general concept into concrete code. To remedy this I will try to show few examples of how to build a web application from ground up. But I can't fit all of that into a single blog post ... So lets get started at the beginning...<br /><br />Here is what your main method should look like (no matter how complex your application) if you are using GUICE: (<a href="http://code.google.com/p/unit-test-teaching-examples/source/browse/trunk/src/di/webserver/GuiceDI.java">src</a>)<br /><pre>public static void main(String[] args)<br /> throws Exception {<br /> // Creation Phase<br /> Injector injector = Guice.createInjector(<br /> new CalculatorServerModule(args));<br /> Server server = injector.getInstance(Server.class);<br /> // Run Phase<br /> server.start();<br />}</pre><br />Or if you want to do manual dependency injection: (<a href="http://code.google.com/p/unit-test-teaching-examples/source/browse/trunk/src/di/webserver/ManualDI.java?r=6">src</a>)<br /><pre>public static void main(String[] args)<br /> throws Exception {<br /> // Creation Phase<br /> Server server = new ServerFactory(args)<br /> .createServer();<br /> // Run Phase<br /> server.start();<br />}</pre><br />The truth is I don't know how to test the main method. The main method is static and as a result there are no places where we can inject test-doubles. (I know we can fight static with static, but we already said that global state is bad <a href="http://misko.hevery.com/2008/08/25/root-cause-of-singletons/">here</a>, <a href="http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/">here</a> and <a href="http://misko.hevery.com/2008/07/24/how-to-write-3v1l-untestable-code/">here</a>). The reason we can't test this is that the moment you execute the main method the whole application runs, and that is not what we want and there is nothing we can do to prevent that.<br /><br />But the method is so short that I don't bother testing it since it has some really cool properties:<br /><ol><br /> <li>Notice how the creation-phase contains the code which builds the object graph of the application. The last line runs the application. The separation is very important. We can test the ServerFactory in isolation. Passing it different arguments and than asserting that the correct object graph got built. But, in order to do that the Factory class should do nothing but object graph construction. The object constructors better do nothing but field assignments. No reading of files, starting of threads, or any other work which would cause problems in unit-test. All we do is simply instantiate some graph of objects. The graph construction is controlled by the command line arguments which we passed into the constructor. So we can test creation-phase in isolation with unit-test. (Same applies for GUICE example)</li><br /> <li>The last line gets the application running. Here is where you can do all of your fun threads, file IO etc code. However, because the application is build from lots of objects collaborating together it is easy to test each object in isolation. In test I just instantiate the Server and pass in some test doubles in the constructor to mock out the not so interesting/hard to test code.</li><br /></ol><br />As you can see we have a clear separation of the object graph construction responsibility from the application logic code. If you were to examine the code in more detail you would find that all of the new operators have migrated from the run-phase to creation-phase (See <a href="http://misko.hevery.com/2008/07/08/how-to-think-about-the-new-operator/">How to Think About the &#8220;new&#8221; Operator</a>) And that is very important. New operator in application code is enemy of testing, but new in tests and factories is your friend. (The reason is that in tests we want to use test-doubles which are usually a subclass or an implementation of the parent class. If application code calls new than you can never replace that new with a subclass or different implementation.) The key is that the object creation responsibility and the the application code are two different responsibilities and they should not be mixed. Especially in the main method!<br /><br />A good way to think about this is that you want to design your application such that you can control the application behavior by controlling the way you wire the objects together (Object collaborator graph). Whether you wire in a InMemory, File or Database repository, PopServer or IMAPServer, LDAP or file based authentication. All these different behaviors should manifest themselves as different object graphs. The knowledge of how to wire the objects together should be stored in your factory class. If you want to prevent something from running in a test, you don't place an if statement in front of it. Instead you wire up a different graph of objects. You wire NullAthenticator in place of LDAPAuthenticator. Wiring your objects differently is how the tests determines what gets run and what gets mocked out. This is why it is important for the tests to have control of the new operators (or putting it differently the application code does not have the new operators). This is why we don't know how to test the main method. Main method is static and hence procedural. I don't know how to test procedural code since there is nothing to wire differently. I can't wire the call graph different in procedural world to prevent things from executing, the call graph is determined at compile time.<br /><br />In my experience that main method usually is some of the scariest code I have seen. Full of singleton initialization and threads. Completely untestable. What you want is that each object simply declares its dependencies in its constructor. (Here is the list of things I need to know about) Then when you start to write the Factory it will practically write itself. You simply try to new the object you need to return, which declares its dependencies, you in turn try to new those dependencies, etc... If there are some singletons you just have to make sure that you call the new operator only once. But more on factories in our next blog post... <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:My main() Method Is Better Than Yours&url=https://testing.googleblog.com/2008/09/my-main-method-is-better-than-yours.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/09/my-main-method-is-better-than-yours.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'> &#57529; </i> <a href='https://testing.googleblog.com/2008/09/my-main-method-is-better-than-yours.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/09/my-main-method-is-better-than-yours.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/Misko%20Hevery' rel='tag'> Misko Hevery </a> </span> </div> </div> </div> <div class='post' data-id='3860966436609827508' itemscope='' itemtype='http://schema.org/BlogPosting'> <h2 class='title' itemprop='name'> <a href='https://testing.googleblog.com/2008/09/tott-data-driven-traps.html' itemprop='url' title='TotT: Data Driven Traps!'> TotT: Data Driven Traps! </a> </h2> <div class='post-header'> <div class='published'> <span class='publishdate' itemprop='datePublished'> Thursday, September 04, 2008 </span> </div> </div> <div class='post-body'> <div class='post-content' itemprop='articleBody'> <script type='text/template'> When writing a unit test, it is tempting to exercise many scenarios by writing a data-driven test. For example, to test the function IsWord, you could write (ARRAYSIZE is a macro that returns the number of elements in an array):<br /><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%;">const struct {const char* word; bool is_word;} test_data[] = {</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;{"milk", true}, {"centre", false}, {"jklm", false},</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">};</span><br /><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">TEST(IsWordTest, TestEverything) {</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;for (int i = 0; i &lt; ARRAYSIZE(test_data); i++)</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;&nbsp;&nbsp;EXPECT_EQ(test_data[i].is_word, IsWord(test_data[i].word));</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">}</span><br /></p><br /><br />This keeps the test code short and makes it easy to add new tests but makes it hard to identify a failing test assertion (and to get the debugger to stop in the right place). As your code grows the test data tends to grow <b><span style="color:#800000;">faster than linearly</span></b>. For example, if you add a parameter called locale to IsWord, the test could become:<br /><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%;"> Locale LOCALES[] = { Word::US, Word::UK, Word::France, ... };</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">const struct {const char* word; bool is_word[NUM_LOCALES];} data[] = {</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;{"milk", {true, true, false, ...}}, // one bool per language</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;{"centre", {false, true, true, ...}}, </span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;{"jklm", {false, false, false, ...}}</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">};</span><br /> <br /><span style=" ;font-family:courier new, monospace;font-size:100%;">TEST(IsWordTest, TestEverything) {</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;for (int i = 0; i &lt; ARRAYSIZE(data); i++) </span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;&nbsp;&nbsp;for (int j = 0; j &lt; ARRAYSIZE(LOCALES); j++) </span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EXPECT_EQ(data[i].is_word[j], IsWord(data[i].word, LOCALES[i]));</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">}</span><br /></p><br /><br />The change was relatively easy to make: change the data structure, fill in the boolean values for other locales and add a loop to the test code. But even this small changed has made the test harder to read and slower as it repeats potentially unnecessary checks. In addition, both the test AND the code have changed. How do you know the test is not broken? (Actually, it is broken. Can you see the bug?) By contrast, <b><span style="color:#800000;">keeping the data in the test</span></b> gives us:<br /><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%;"> TEST(IsWordTest, IsWordInMultipleLocales) {</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;EXPECT_TRUE(IsWord("milk", Word::UK)); </span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;EXPECT_TRUE(IsWord("milk", Word::US));</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;EXPECT_FALSE(IsWord("milk", Word::France));</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">}</span><br /><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">TEST(IsWordTest, IsWordWithNonExistentWord) { // 'jklm' test is not repeated </span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;EXPECT_FALSE(IsWord("jklm", Word::US)); // as it uses the same code path</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">}</span><br /></p><br /><br />The difference between these two code snippets is minor but real-life data-driven tests quickly become <b><span style="color:#800000;">unmanageable</span></b>. A complete example would not fit on this page but if you look at your code base, you will find a few specimens lurking in some (not-so) forgotten test classes. They can be identified by their large size, vague names and the fact that they provide little to no information about why they fail.<br /><br />Remember to download <a href="http://code.google.com/testing/TotT-2008-09-04.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> When writing a unit test, it is tempting to exercise many scenarios by writing a data-driven test. For example, to test the function IsWord, you could write (ARRAYSIZE is a macro that returns the number of elements in an array):<br /><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%;">const struct {const char* word; bool is_word;} test_data[] = {</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;{"milk", true}, {"centre", false}, {"jklm", false},</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">};</span><br /><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">TEST(IsWordTest, TestEverything) {</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;for (int i = 0; i &lt; ARRAYSIZE(test_data); i++)</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;&nbsp;&nbsp;EXPECT_EQ(test_data[i].is_word, IsWord(test_data[i].word));</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">}</span><br /></p><br /><br />This keeps the test code short and makes it easy to add new tests but makes it hard to identify a failing test assertion (and to get the debugger to stop in the right place). As your code grows the test data tends to grow <b><span style="color:#800000;">faster than linearly</span></b>. For example, if you add a parameter called locale to IsWord, the test could become:<br /><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%;"> Locale LOCALES[] = { Word::US, Word::UK, Word::France, ... };</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">const struct {const char* word; bool is_word[NUM_LOCALES];} data[] = {</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;{"milk", {true, true, false, ...}}, // one bool per language</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;{"centre", {false, true, true, ...}}, </span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;{"jklm", {false, false, false, ...}}</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">};</span><br /> <br /><span style=" ;font-family:courier new, monospace;font-size:100%;">TEST(IsWordTest, TestEverything) {</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;for (int i = 0; i &lt; ARRAYSIZE(data); i++) </span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;&nbsp;&nbsp;for (int j = 0; j &lt; ARRAYSIZE(LOCALES); j++) </span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EXPECT_EQ(data[i].is_word[j], IsWord(data[i].word, LOCALES[i]));</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">}</span><br /></p><br /><br />The change was relatively easy to make: change the data structure, fill in the boolean values for other locales and add a loop to the test code. But even this small changed has made the test harder to read and slower as it repeats potentially unnecessary checks. In addition, both the test AND the code have changed. How do you know the test is not broken? (Actually, it is broken. Can you see the bug?) By contrast, <b><span style="color:#800000;">keeping the data in the test</span></b> gives us:<br /><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%;"> TEST(IsWordTest, IsWordInMultipleLocales) {</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;EXPECT_TRUE(IsWord("milk", Word::UK)); </span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;EXPECT_TRUE(IsWord("milk", Word::US));</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;EXPECT_FALSE(IsWord("milk", Word::France));</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">}</span><br /><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">TEST(IsWordTest, IsWordWithNonExistentWord) { // 'jklm' test is not repeated </span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">&nbsp;&nbsp;EXPECT_FALSE(IsWord("jklm", Word::US)); // as it uses the same code path</span><br /><span style=" ;font-family:courier new, monospace;font-size:100%;">}</span><br /></p><br /><br />The difference between these two code snippets is minor but real-life data-driven tests quickly become <b><span style="color:#800000;">unmanageable</span></b>. A complete example would not fit on this page but if you look at your code base, you will find a few specimens lurking in some (not-so) forgotten test classes. They can be identified by their large size, vague names and the fact that they provide little to no information about why they fail.<br /><br />Remember to download <a href="http://code.google.com/testing/TotT-2008-09-04.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: Data Driven Traps!&url=https://testing.googleblog.com/2008/09/tott-data-driven-traps.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/09/tott-data-driven-traps.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'> &#57529; </i> <a href='https://testing.googleblog.com/2008/09/tott-data-driven-traps.html#comments' style='font-weight: 500; text-decoration: underline;'>8 comments</a> </div> <div class='post-footer'> <div class='cmt_iframe_holder' data-href='https://testing.googleblog.com/2008/09/tott-data-driven-traps.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='blog-pager' id='blog-pager'> <a class='home-link' href='https://testing.googleblog.com/'> <i class='material-icons'> &#59530; </i> </a> <span id='blog-pager-newer-link'> <a class='blog-pager-newer-link' href='https://testing.googleblog.com/search?updated-max=2008-10-22T07:56:00-07:00&max-results=5&reverse-paginate=true' id='Blog1_blog-pager-newer-link' title='Newer Posts'> <i class='material-icons'> &#58820; </i> </a> </span> <span id='blog-pager-older-link'> <a class='blog-pager-older-link' href='https://testing.googleblog.com/search?updated-max=2008-09-04T15:54:00-07:00&max-results=5' id='Blog1_blog-pager-older-link' title='Older Posts'> <i class='material-icons'> &#58824; </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'> &#58821; </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'> 102 </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'> 30 </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'> 12 </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/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/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&#39;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'> &#58055; </i> <h2> Archive </h2> <i class='material-icons arrow'> &#58821; </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'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2024/'> 2024 </a> <span class='post-count' dir='ltr'>(12)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9660;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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 expanded'> <a class='toggle' href='javascript:void(0)'> <span class='zippy toggle-open'> &#9660;&#160; </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2008/09/'> Sep </a> <span class='post-count' dir='ltr'>(8)</span> <ul class='posts'> <li> <a href='https://testing.googleblog.com/2008/09/by-miko-hevery-we-talked-about-how-it.html'> by Miško Hevery We talked about how it i... </a> </li> <li> <a href='https://testing.googleblog.com/2008/09/tott-mockin-ur-objectz.html'> TotT: Mockin Ur Objectz </a> </li> <li> <a href='https://testing.googleblog.com/2008/09/presubmit-and-performance.html'> Presubmit And Performance </a> </li> <li> <a href='https://testing.googleblog.com/2008/09/google-maps-api-open-sources-their.html'> The Google Maps API Open Source Their Selenium Tes... </a> </li> <li> <a href='https://testing.googleblog.com/2008/09/where-have-all-new-operators-gone.html'> Where Have all the &quot;new&quot; Operators Gone? </a> </li> <li> <a href='https://testing.googleblog.com/2008/09/test-first-is-fun_08.html'> Test first is fun! </a> </li> <li> <a href='https://testing.googleblog.com/2008/09/my-main-method-is-better-than-yours.html'> My main() Method Is Better Than Yours </a> </li> <li> <a href='https://testing.googleblog.com/2008/09/tott-data-driven-traps.html'> TotT: Data Driven Traps! </a> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </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'> &#9658;&#160; </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 collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://testing.googleblog.com/2008/06/'> Jun </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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'> &#9658;&#160; </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_v6XV70aJ38cWZxZ5AUccXyVzrC6fN9eXQiZNR4kxKmWW9dsGx6GSbXJdyVH7Ofhzhj4jIpgIa0v44q8wYlDS5PScJpMXy-hssmqkKUIXIeDzmLM9_lR0W26yd2cu1QWbW-J39VnSz0rGewZPm1ihM=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/&amp;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/984859869-widgets.js"></script> <script type='text/javascript'> window['__wavt'] = 'AOuZoY5t1IMFxbuePCgTxcvusLTosT139g:1732444842869';_WidgetManager._Init('//www.blogger.com/rearrange?blogID\x3d15045980','//testing.googleblog.com/2008/09/','15045980'); _WidgetManager._SetDataContext([{'name': 'blog', 'data': {'blogId': '15045980', 'title': 'Google Testing Blog', 'url': 'https://testing.googleblog.com/2008/09/', 'canonicalUrl': 'https://testing.googleblog.com/2008/09/', '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/d78375fb222d99b3', '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': 'September 2008', 'pageTitle': 'Google Testing Blog: September 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/09/', 'type': 'feed', 'isSingleItem': false, 'isMultipleItems': true, 'isError': false, 'isPage': false, 'isPost': false, 'isHomepage': false, 'isArchive': true, 'isLabelSearch': false, 'archive': {'year': 2008, 'month': 9, 'rangeMessage': 'Showing posts from September, 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/2646514562-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>

Pages: 1 2 3 4 5 6 7 8 9 10