2012-06-18 15 views
5

Background:Come unità di prova codice Javascript che interagisce con elementi DOM

vengo da Java sfondo, in modo non troppo familiarità con JavaScript.

Stiamo pensando di introdurre JavaScript unità di test sia per il nostro codice esistente (legacy) e il lavoro futuro. Siamo principalmente un negozio di java (Spring, Weblogic ecc.).

Stiamo esaminando le opzioni che ci danno una buona integrazione con IDE (IntelliJ IDEA) e il sonar, oltre ad essere in grado di farli funzionare come parte di integrazione continua.

JsTestDriver sembra spuntare tutte le caselle.

Domanda:

Molto del nostro attuale codice javascript è a) embeded all'interno di JSP e b) utilizza jQuery per interagire con gli elementi della pagina direttamente.

Come dovremmo fare per testare una funzione che è fortemente dipendente sul DOM. Ecco alcuni esempi di codice di funzioni che di cui sto parlando:

function enableOccupationDetailsText(){ 
    $("#fldOccupation").val("Unknown"); 
    $("#fldOccupation_Details").attr("disabled", ""); 
    $("#fldOccupation_Details").val(""); 
    $("#fldOccupation_Details").focus(); 
} 

o

jQuery(document).ready(function(){ 

    var oTable = $('#policies').dataTable({ 
      "sDom" : 'frplitip', 
       "bProcessing": true, 
       "bServerSide": true, 
       "sAjaxSource": "xxxx.do", 
       "sPaginationType": "full_numbers", 
       "aaSorting": [[ 1, "asc" ]], 
       "oLanguage": { 
        "sProcessing": "Processing...", 
        "sLengthMenu": "Show _MENU_ policies", 
        "sZeroRecords": "No matching policies found", 
        "sInfo":   "Showing _START_ to _END_ of _TOTAL_ policies", 
        "sInfoEmpty": "Showing 0 to 0 of 0 policies", 
        "sInfoFiltered": "(filtered from _MAX_ total policies)", 
        "sInfoPostFix": "", 
        "sSearch":  "Search:", 
        "sUrl":   "", 
        "oPaginate": { 
         "sFirst": "First", 
         "sPrevious": "Previous", 
         "sNext":  "Next", 
         "sLast":  "Last" 
       } 
      }, 
       "fnRowCallback": function(nRow, aData, iDisplayIndex, iDisplayIndexFull) { 
         $('td:eq(0)', nRow).html("<a href='/ole/policy/general_details.do?policy_id="+aData[0]+"'>"+aData[0]+"</a>"); 
         return nRow; 

       }, 

       "fnServerData" : function (url, data, callback, settings) { 

       settings.jqXHR = $.ajax({ 
        "url": url, 
        "data": data, 
        "success": function (json) { 
         if (json.errorMessage != null) { 
          var an = settings.aanFeatures.r; 
          an[0].style.fontSize="18px"; 
          an[0].style.backgroundColor="red"; 
          an[0].style.height="70px"; 
          an[0].innerHTML=json.errorMessage; 
          setTimeout('window.location="/xxxx"',1000); 
          //window.location="/xxxxx"; 
         } else { 
          $(settings.oInstance).trigger('xhr', settings); 
          callback(json); 
         } 
        }, 
        "dataType": "json", 
        "cache": false, 
        "error": function (xhr, error, thrown) { 
         if (error == "parsererror") { 
          alert("Unexpected error, please contact system administrator. Press OK to be redirected to home page."); 
          window.location="/xxxx"; 
         } 
        } 
       }); 
       } 

      }); 
     $("#policies_filter :text").attr('id', 'fldKeywordSearch'); 
     $("#policies_length :input").attr('id', 'fldNumberOfRows'); 
     $("body").find("span > span").css("border","3px solid red"); 
     oTable.fnSetFilteringDelay(500); 
     oTable.fnSearchHighlighting(); 
     $("#fldKeywordSearch").focus(); 

} 
); 

In quest'ultimo caso, il mio approccio è che la funzione in questione è troppo grande e deve essere rotto a più piccolo (unità) in modo che possa essere testato. Ma tutti i punti di interazione con DOM, jQuery, datatables, ajax etc rendono davvero complicato il refactoring nel modo in cui lo facciamo nel mondo Java per renderlo più testabile.

Così, qualche suggerimento per quanto sopra per assaggiare i casi sarebbe molto apprezzato!

+2

Vedere anche [Testing DOM che manipola nel test Jasmine] (http://stackoverflow.com/questions/7672389/testing-dom-manipulating-in-jasmine-test) –

+0

controlla anche phantomjs headless webkit – obimod

risposta

6

Per verificare il codice seguente:

function enableOccupationDetailsText(){ 
    $("#fldOccupation").val("Unknown"); 
    $("#fldOccupation_Details").attr("disabled", ""); 
    $("#fldOccupation_Details").val(""); 
    $("#fldOccupation_Details").focus(); 
} 

è possibile utilizzare il seguente codice:

// First, create the elements 
$('<input>', { id: 'fldOccupation' }).appendTo(document.body); 
$('<input>', { disabled: true, id: 'fldOccupation_Details' }) 
    .appendTo(document.body); 

// Then, run the function to test 
enableOccupationDetailsText(); 

// And test 
assert($('#fldOccupation').val(), 'Unknown'); 
assert($('#fldOccupation_Details').prop('disabled'), false); 

Come vedi, è solo il classico setup > run > assert modello.

+0

che dire di abbattere quegli oggetti DOM in modo da non avere un test che interferisce con un altro? Sarebbe una buona pratica? Se é cosi, come? –

+2

@GregWoods bene, puoi rimuoverli con qualcosa come '$ ('# fldOccupation'). Remove(); $ ('# fldOccupation_Details'). remove(); 'o semplicemente' $ (document.body.children) .remove(); ' –

4

forse Selenio/SeleniumGrid è utile per voi: http://seleniumhq.org/

Non è un "unittest" per definizione, ma è possibile scrivere i test di selenio con Java o Python (e molti altri ...), come test di unità. Seleniumtests avvia test web in browser reali, ed è silenzioso per testare frontend (e manipolazioni dom).

Edit: oggi mi sono imbattuto su questo sito che descrive modi diversi per unit test soprattutto in un jQuery sfondo: http://addyosmani.com/blog/jquery-testing-tools/