Testing sucks
Upcoming SlideShare
Loading in...5
×
 

Testing sucks

on

  • 1,300 views

Presentation given in BrazilJS 2012

Presentation given in BrazilJS 2012

Statistics

Views

Total Views
1,300
Views on SlideShare
1,278
Embed Views
22

Actions

Likes
7
Downloads
20
Comments
2

2 Embeds 22

http://www.linkedin.com 18
https://twitter.com 4

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Testing sucks Testing sucks Presentation Transcript

  • Testing Sucks Leo Balter - BrazilJS 2012 JS
  • Testar é chato!
  • Testes vs Testar!
  • Testes humanos • Repetitivos • Estressantes • Cansativos
  • Concentração polarizada• Nos concentramos em um único ponto• Não vemos os demais• falsa sensação de segurança
  • OlharViciado
  • Testes de Trollagem
  • Pare de “ficar testando” seu código
  • JSHint/JSLint não testa código!• Convenção de estilo• Erros comuns• “As Boas Partes”
  • Mito doCompilador
  • Pânico vs Benefícios• Muito fácil criar testes para algo que ainda não existe• Não tão simples quando a aplicação já existe e está “no ar”.
  • Aplicaçãonão testada
  • A Síndrome do “o que estáfuncionando nãose deve mexer”.
  • Quebre a aplicação!• Criamos testes simples que passem• Teste o que está em produção• Cobertura de testes• O que é crítico?• Especificação• O que falta testar?• Testes de Trollagem
  • Acredite:Sua aplicação vai falhar!
  • Já viu essa síndrome?• Não vai ao médico pra evitar descobrir um mal grave• Pode haver um problema latente que vai falhar em um momento crítico• Pode acabar em morte
  • Na aplicação• Não testamos para não descobrir o que falha• Há problemas latentes que vão falhar em momentos críticos (Por exemplo: um sistema de pagamento do seu e-commerce)• Sua empresa morre (vai a falência)
  • Estabeleça o que é crítico• Quão crítico é cada parte do seu sistema?• Se não funcionar, quais as consequências?
  • Alto Ri sc o C Ri rí t sc ico o deOcorrência Ri ní sc ve o ml de éd ba io ix o ní ve Baixo l Baixo Impacto Alto Gerenciamento de Risco http://bit.ly/11tTwN
  • Automatização• --Retrabalho• --Surpresas• Mais tempo para o que é interessante• Menos tempo para testar tudo novamente
  • Automatização• --Retrabalho• --Surpresas• Mais tempo para o que é interessante• Menos tempo para testar tudo novamente
  • Metodologias Ágeis• Aplicar testes é uma rotina contida em Metodologias Ágeis• Testes não dependem de metodologias ágeis• Ex.: jQuery
  • FuncionaFaz o que deveria
  • Esse código funciona! • Um código pode funcionar perfeitamente • Estar 100% testado • e não cumprir 10% do seu papel
  • Fluxo
  • EspecificaçãoFluxo
  • Especificação Plano de TestesFluxo
  • Especificação Plano de TestesFluxo Testes
  • Validação
  • ValidaçãoPlano de Testes
  • ValidaçãoPlano de Testes Especificação
  • ValidaçãoPlano de Testes Testes Especificação
  • ValidaçãoPlano de Testes Testes Especificação Aplicação
  • Testes não validam especificação!Testes não criam especificação!
  • Testes vs Especificação• Se os testes validassem especificação, não poderiamos prever correções de bugs e comportamentos de ambientes.• Bugs não fazem parte de uma especificação.
  • Teste que Falha Código Refatorar Baby Steps (Testes Unitários)
  • Sempre em Baby Steps• Ótimo para pegar o ritmo• função 1, 2, 3, pin• Treino do Lutador
  • Cobertura de Código
  • function foo( bar ) { if ( bar ) { console.log( yes! ); else { console.log( no! ); }}
  • function foo( bar ) { if ( bar ) { console.log( yes! ); else { console.log( no! ); }}
  • function foo( bar ) { if ( bar ) { console.log( yes! ); else { console.log( no! ); }}
  • function foo( bar ) { if ( bar ) { console.log( yes! ); else { console.log( no! ); }}
  • function foo( bar ) { if ( bar ) { console.log( yes! ); else { console.log( no! ); }}
  • function foo( bar ) { if ( bar ) { console.log( yes! ); else { console.log( no! ); }}
  • Código 100% coberto por testes!
  • • JSCoverage• CoverJS
  • Tudo é testável• Complexidade vs Criticidade• window.location.replace()
  • JSTestes em JavaScript
  • Testes UnitáriosInterface FuncionaisDesempenho Integração
  • Open Webvários ambientes
  • FirefoxChrome Opera IE 8, 9[, 10, ...]
  • FirefoxChrome Mobile Opera IE 8, 9[, 10, ...]
  • PhantomJS Webkit
  • Ferramentas QUnit NodeUnitMocha Vows Jasmine
  • Estilos de TestesTDD BDD Exports
  • TDDmodule( "Basics" );test( "hello test", function() {  ok( 1 == "1", "Passed!" );}); http://qunitjs.com/
  • TDDmodule( "Basics" );test( "hello test", function() {  ok( 1 == "1", "Passed!" );}); http://qunitjs.com/
  • TDDmodule( "Basics" );test( "hello test", function() {  ok( 1 == "1", "Passed!" );}); http://qunitjs.com/
  • TDDmodule( "Basics" );test( "hello test", function() {  ok( 1 == "1", "Passed!" );}); http://qunitjs.com/
  • TDDmodule( "Basics" );test( "hello test", function() {  ok( 1 == "1", "Passed!" );}); http://qunitjs.com/
  • TDDmodule( "Basics" );test( "hello test", function() {  ok( 1 == "1", "Passed!" );}); http://qunitjs.com/
  • TDDmodule( "Basics" );test( "hello test", function() {  ok( 1 == "1", "Passed!" );}); http://qunitjs.com/
  • TDDmodule( "Basics" );test( "hello test", function() {  ok( 1 == "1", "Passed!" );}); http://qunitjs.com/
  • TDDmodule( "Basics" );test( "hello test", function() {  ok( 1 == "1", "Passed!" );}); http://qunitjs.com/
  • <!DOCTYPE html><html><head>  <meta charset="utf-8">  <title>QUnit Example</title>  <link rel="stylesheet" href="/t/qunit.css"></head><body>  <div id="qunit"></div>  <script src="/t/qunit.js"></script> <script src="/js/script.js"></script>  <script src="/t/unit/tests.js"></script></body></html>
  • <!DOCTYPE html><html><head>  <meta charset="utf-8">  <title>QUnit Example</title>  <link rel="stylesheet" href="/t/qunit.css"></head><body>  <div id="qunit"></div>  <script src="/t/qunit.js"></script> <script src="/js/script.js"></script>  <script src="/t/unit/tests.js"></script></body></html>
  • <!DOCTYPE html><html><head>  <meta charset="utf-8">  <title>QUnit Example</title>  <link rel="stylesheet" href="/t/qunit.css"></head><body>  <div id="qunit"></div>  <script src="/t/qunit.js"></script> <script src="/js/script.js"></script>  <script src="/t/unit/tests.js"></script></body></html>
  • <!DOCTYPE html><html><head>  <meta charset="utf-8">  <title>QUnit Example</title>  <link rel="stylesheet" href="/t/qunit.css"></head><body>  <div id="qunit"></div>  <script src="/t/qunit.js"></script> <script src="/js/script.js"></script>  <script src="/t/unit/tests.js"></script></body></html>
  • <!DOCTYPE html><html><head>  <meta charset="utf-8">  <title>QUnit Example</title>  <link rel="stylesheet" href="/t/qunit.css"></head><body>  <div id="qunit"></div>  <script src="/t/qunit.js"></script> <script src="/js/script.js"></script>  <script src="/t/unit/tests.js"></script></body></html>
  • <!DOCTYPE html><html><head>  <meta charset="utf-8">  <title>QUnit Example</title>  <link rel="stylesheet" href="/t/qunit.css"></head><body>  <div id="qunit"></div>  <script src="/t/qunit.js"></script> <script src="/js/script.js"></script>  <script src="/t/unit/tests.js"></script></body></html>
  • <!DOCTYPE html><html><head>  <meta charset="utf-8">  <title>QUnit Example</title>  <link rel="stylesheet" href="/t/qunit.css"></head><body>  <div id="qunit"></div>  <script src="/t/qunit.js"></script> <script src="/js/script.js"></script>  <script src="/t/unit/tests.js"></script></body></html>
  • <!DOCTYPE html><html><head>  <meta charset="utf-8">  <title>QUnit Example</title>  <link rel="stylesheet" href="/t/qunit.css"></head><body>  <div id="qunit"></div>  <script src="/t/qunit.js"></script> <script src="/js/script.js"></script>  <script src="/t/unit/tests.js"></script></body></html>
  • <!DOCTYPE html><html><head>  <meta charset="utf-8">  <title>QUnit Example</title>  <link rel="stylesheet" href="/t/qunit.css"></head><body>  <div id="qunit"></div>  <script src="/t/qunit.js"></script> <script src="/js/script.js"></script>  <script src="/t/unit/tests.js"></script></body></html>
  • BDDdescribe("A suite", function() { it("spec with an expectation", function(){ expect(true).toBe(true); });});
  • BDDdescribe("A suite", function() { it("spec with an expectation", function(){ expect(true).toBe(true); });});
  • BDDdescribe("A suite", function() { it("spec with an expectation", function(){ expect(true).toBe(true); });});
  • BDDdescribe("A suite", function() { it("spec with an expectation", function(){ expect(true).toBe(true); });});
  • BDDdescribe("A suite", function() { it("spec with an expectation", function(){ expect(true).toBe(true); });});
  • BDDdescribe("A suite", function() { it("spec with an expectation", function(){ expect(true).toBe(true); });});
  • Exportsmodule.exports = { test1: function (test) { test.equals(this.foo, bar); test.done(); }};
  • Exportsmodule.exports = { test1: function (test) { test.equals(this.foo, bar); test.done(); }};
  • Exportsmodule.exports = { test1: function (test) { test.equals(this.foo, bar); test.done(); }};
  • Exportsmodule.exports = { test1: function (test) { test.equals(this.foo, bar); test.done(); }};
  • Exportsmodule.exports = { test1: function (test) { test.equals(this.foo, bar); test.done(); }};
  • Comocomeçar?
  • HTML Estático JavaScript Testes
  • <!DOCTYPE html><html><head>  <meta charset="utf-8">  <title>QUnit Example</title>  <link rel="stylesheet" href="/t/qunit.css"></head><body>  <div id="qunit"></div>  <div id="qunit-fixtures"> <div id="foo">bar</div> </div>  <script src="/t/qunit.js"></script> <script src="/js/script.js"></script>  <script src="/t/unit/tests.js"></script></body></html>
  • <!DOCTYPE html><html><head>  <meta charset="utf-8">  <title>QUnit Example</title>  <link rel="stylesheet" href="/t/qunit.css"></head><body>  <div id="qunit"></div>  <div id="qunit-fixtures"> <div id="foo">bar</div> </div>  <script src="/t/qunit.js"></script> <script src="/js/script.js"></script>  <script src="/t/unit/tests.js"></script></body></html>
  • Código testado tem bom desempenho?• Testes unitários não medem desempenho• Existem testes de desempenho• Código sem erros pode evitar lentidão
  • DexterJS
  • Dexter.spy
  • function carly( crazy ) { if ( typeof ( crazy ) === number ) { return Call me maybe?; } else { return Hey, I just met you!, and this is + crazy; }}function meSad( maybe ) { return carly( maybe ? 5555555 : crazy! );} http://jsbin.com/osijuq/7/edit
  • function carly( crazy ) { if ( typeof ( crazy ) === number ) { return Call me maybe?; } else { return Hey, I just met you!, and this is + crazy; }}function meSad( maybe ) { return carly( maybe ? 5555555 : crazy! );} http://jsbin.com/osijuq/7/edit
  • function carly( crazy ) { if ( typeof ( crazy ) === number ) { return Call me maybe?; } else { return Hey, I just met you!, and this is + crazy; }}function meSad( maybe ) { return carly( maybe ? 5555555 : crazy! );} http://jsbin.com/osijuq/7/edit
  • function carly( crazy ) { if ( typeof ( crazy ) === number ) { return Call me maybe?; } else { return Hey, I just met you!, and this is + crazy; }}function meSad( maybe ) { return carly( maybe ? 5555555 : crazy! );} http://jsbin.com/osijuq/7/edit
  • function carly( crazy ) { if ( typeof ( crazy ) === number ) { return Call me maybe?; } else { return Hey, I just met you!, and this is + crazy; }}function meSad( maybe ) { return carly( maybe ? 5555555 : crazy! );} http://jsbin.com/osijuq/7/edit
  • function carly( crazy ) { if ( typeof ( crazy ) === number ) { return Call me maybe?; } else { return Hey, I just met you!, and this is + crazy; }}function meSad( maybe ) { return carly( maybe ? 5555555 : crazy! );} http://jsbin.com/osijuq/7/edit
  • function carly( crazy ) { if ( typeof ( crazy ) === number ) { return Call me maybe?; } else { return Hey, I just met you!, and this is + crazy; }}function meSad( maybe ) { return carly( maybe ? 5555555 : crazy! );} http://jsbin.com/osijuq/7/edit
  • test( carly(), 4, function() { var spy = Dexter.spy( window, carly, function( arg1 ) { equal( arg1, crazy!, me sad got crazy! ); }); meSad( false ); equal( spy.called, 1, carly was called once ); spy.callback = 0; equal( meSad( true ), Call me maybe?, keep asking ); equal( spy.called, 2, carly called again! ); spy.restore();});
  • test( carly(), 4, function() { var spy = Dexter.spy( window, carly, function( arg1 ) { equal( arg1, crazy!, me sad got crazy! ); }); meSad( false ); equal( spy.called, 1, carly was called once ); spy.callback = 0; equal( meSad( true ), Call me maybe?, keep asking ); equal( spy.called, 2, carly called again! ); spy.restore();});
  • test( carly(), 4, function() { var spy = Dexter.spy( window, carly, function( arg1 ) { equal( arg1, crazy!, me sad got crazy! ); }); meSad( false ); equal( spy.called, 1, carly was called once ); spy.callback = 0; equal( meSad( true ), Call me maybe?, keep asking ); equal( spy.called, 2, carly called again! ); spy.restore();});
  • test( carly(), 4, function() { var spy = Dexter.spy( window, carly, function( arg1 ) { equal( arg1, crazy!, me sad got crazy! ); }); meSad( false ); equal( spy.called, 1, carly was called once ); spy.callback = 0; equal( meSad( true ), Call me maybe?, keep asking ); equal( spy.called, 2, carly called again! ); spy.restore();});
  • test( carly(), 4, function() { var spy = Dexter.spy( window, carly, function( arg1 ) { equal( arg1, crazy!, me sad got crazy! ); }); meSad( false ); equal( spy.called, 1, carly was called once ); spy.callback = 0; equal( meSad( true ), Call me maybe?, keep asking ); equal( spy.called, 2, carly called again! ); spy.restore();});
  • test( carly(), 4, function() { var spy = Dexter.spy( window, carly, function( arg1 ) { equal( arg1, crazy!, me sad got crazy! ); }); meSad( false ); equal( spy.called, 1, carly was called once ); spy.callback = 0; equal( meSad( true ), Call me maybe?, keep asking ); equal( spy.called, 2, carly called again! ); spy.restore();});
  • test( carly(), 4, function() { var spy = Dexter.spy( window, carly, function( arg1 ) { equal( arg1, crazy!, me sad got crazy! ); }); meSad( false ); equal( spy.called, 1, carly was called once ); spy.callback = 0; equal( meSad( true ), Call me maybe?, keep asking ); equal( spy.called, 2, carly called again! ); spy.restore();});
  • test( carly(), 4, function() { var spy = Dexter.spy( window, carly, function( arg1 ) { equal( arg1, crazy!, me sad got crazy! ); }); meSad( false ); equal( spy.called, 1, carly was called once ); spy.callback = 0; equal( meSad( true ), Call me maybe?, keep asking ); equal( spy.called, 2, carly called again! ); spy.restore();});
  • test( carly(), 4, function() { var spy = Dexter.spy( window, carly, function( arg1 ) { equal( arg1, crazy!, me sad got crazy! ); }); meSad( false ); equal( spy.called, 1, carly was called once ); spy.callback = 0; equal( meSad( true ), Call me maybe?, keep asking ); equal( spy.called, 2, carly called again! ); spy.restore();});
  • test( carly(), 4, function() { var spy = Dexter.spy( window, carly, function( arg1 ) { equal( arg1, crazy!, me sad got crazy! ); }); meSad( false ); equal( spy.called, 1, carly was called once ); spy.callback = 0; equal( meSad( true ), Call me maybe?, keep asking ); equal( spy.called, 2, carly called again! ); spy.restore();});
  • test( carly(), 4, function() { var spy = Dexter.spy( window, carly, function( arg1 ) { equal( arg1, crazy!, me sad got crazy! ); }); meSad( false ); equal( spy.called, 1, carly was called once ); spy.callback = 0; equal( meSad( true ), Call me maybe?, keep asking ); equal( spy.called, 2, carly called again! ); spy.restore();});
  • test( carly(), 4, function() { var spy = Dexter.spy( window, carly, function( arg1 ) { equal( arg1, crazy!, me sad got crazy! ); }); meSad( false ); equal( spy.called, 1, carly was called once ); spy.callback = 0; equal( meSad( true ), Call me maybe?, keep asking ); equal( spy.called, 2, carly called again! ); spy.restore();});
  • Dexter.stub
  • function carly( crazy ) { if ( typeof ( crazy ) === number ) { return Call me maybe?; } else { return Hey, I just met you!, and this is + crazy; }}function meSad( maybe ) { return carly( maybe ? 5555555 : crazy! );}
  • test( stubbed carly(), 1, function() { var stub = Dexter.stub( window, carly, function() { return relax; }); equal( meSad( true ), relax, stubbed carly! ); stub.restore();});
  • test( stubbed carly(), 1, function() { var stub = Dexter.stub( window, carly, function() { return relax; }); equal( meSad( true ), relax, stubbed carly! ); stub.restore();});
  • test( stubbed carly(), 1, function() { var stub = Dexter.stub( window, carly, function() { return relax; }); equal( meSad( true ), relax, stubbed carly! ); stub.restore();});
  • test( stubbed carly(), 1, function() { var stub = Dexter.stub( window, carly, function() { return relax; }); equal( meSad( true ), relax, stubbed carly! ); stub.restore();});
  • test( stubbed carly(), 1, function() { var stub = Dexter.stub( window, carly, function() { return relax; }); equal( meSad( true ), relax, stubbed carly! ); stub.restore();});
  • test( stubbed carly(), 1, function() { var stub = Dexter.stub( window, carly, function() { return relax; }); equal( meSad( true ), relax, stubbed carly! ); stub.restore();});
  • test( stubbed carly(), 1, function() { var stub = Dexter.stub( window, carly, function() { return relax; }); equal( meSad( true ), relax, stubbed carly! ); stub.restore();});
  • Dexter.fakeXHR
  • test( a fakeXHR, 2, function() { var fakeXHR = Dexter.fakeXHR(); $.get( /ajax.url, function() { ok( true, ajax completed ); }); equal( fakeXHR.requests.length, 1, requests === 1 ); fakeXHR.respond({ body : this is the ajax returned text, headers : { foo2 : bar2 }, status : 200 });});
  • test( a fakeXHR, 2, function() { var fakeXHR = Dexter.fakeXHR(); $.get( /ajax.url, function() { ok( true, ajax completed ); }); equal( fakeXHR.requests.length, 1, requests === 1 ); fakeXHR.respond({ body : this is the ajax returned text, headers : { foo2 : bar2 }, status : 200 });});
  • test( a fakeXHR, 2, function() { var fakeXHR = Dexter.fakeXHR(); $.get( /ajax.url, function() { ok( true, ajax completed ); }); equal( fakeXHR.requests.length, 1, requests === 1 ); fakeXHR.respond({ body : this is the ajax returned text, headers : { foo2 : bar2 }, status : 200 });});
  • test( a fakeXHR, 2, function() { var fakeXHR = Dexter.fakeXHR(); $.get( /ajax.url, function() { ok( true, ajax completed ); }); equal( fakeXHR.requests.length, 1, requests === 1 ); fakeXHR.respond({ body : this is the ajax returned text, headers : { foo2 : bar2 }, status : 200 });});
  • test( a fakeXHR, 2, function() { var fakeXHR = Dexter.fakeXHR(); $.get( /ajax.url, function() { ok( true, ajax completed ); }); equal( fakeXHR.requests.length, 1, requests === 1 ); fakeXHR.respond({ body : this is the ajax returned text, headers : { foo2 : bar2 }, status : 200 });});
  • test( a fakeXHR, 2, function() { var fakeXHR = Dexter.fakeXHR(); $.get( /ajax.url, function() { ok( true, ajax completed ); }); equal( fakeXHR.requests.length, 1, requests === 1 ); fakeXHR.respond({ body : this is the ajax returned text, headers : { foo2 : bar2 }, status : 200 });});
  • test( a fakeXHR, 2, function() { var fakeXHR = Dexter.fakeXHR(); $.get( /ajax.url, function() { ok( true, ajax completed ); }); equal( fakeXHR.requests.length, 1, requests === 1 ); fakeXHR.respond({ body : this is the ajax returned text, headers : { foo2 : bar2 }, status : 200 });});
  • test( a fakeXHR, 2, function() { var fakeXHR = Dexter.fakeXHR(); $.get( /ajax.url, function() { ok( true, ajax completed ); }); equal( fakeXHR.requests.length, 1, requests === 1 ); fakeXHR.respond({ body : this is the ajax returned text, headers : { foo2 : bar2 }, status : 200 });});
  • test( a fakeXHR, 2, function() { var fakeXHR = Dexter.fakeXHR(); $.get( /ajax.url, function() { ok( true, ajax completed ); }); equal( fakeXHR.requests.length, 1, requests === 1 ); fakeXHR.respond({ body : this is the ajax returned text, headers : { foo2 : bar2 }, status : 200 });});
  • test( a fakeXHR, 2, function() { var fakeXHR = Dexter.fakeXHR(); $.get( /ajax.url, function() { ok( true, ajax completed ); }); equal( fakeXHR.requests.length, 1, requests === 1 ); fakeXHR.respond({ body : this is the ajax returned text, headers : { foo2 : bar2 }, status : 200 });});
  • test( a fakeXHR, 2, function() { var fakeXHR = Dexter.fakeXHR(); $.get( /ajax.url, function() { ok( true, ajax completed ); }); equal( fakeXHR.requests.length, 1, requests === 1 ); fakeXHR.respond({ body : this is the ajax returned text, headers : { foo2 : bar2 }, status : 200 });});
  • Começar a criar testes?
  • Experimente!
  • Referências• Coding Dojo• Inicialize um projeto com o GruntJS• TDD - Kent Back• Engenharia de Software - Roger S Pressman• Testable JavaScript - Mark Ethan Trostler *
  • Obrigado! @leobalter leo@balter.com.br JShttp://search.cpan.org/~leobalter/ • @garu_rj • @blabos • @aoqfonseca