2009-04-04 14 views
16

Używam wzorca modułu w Javascript, aby oddzielić mój publiczny interfejs od prywatnej implementacji. Aby uprościć to, co robię, mój kod generuje wykres. Wykres składa się z wielu części (osiach, etykiety, działki, legenda, itp) Mój kod wygląda następująco:Testowanie funkcji prywatnych w javascript

var Graph = function() { 
    var private_data; 
    function draw_legend() { ... } 
    function draw_plot() { ... } 
    function helper_func() { ... } 
    ... 

    return { 
    add_data: function(data) { 
     private_data = data; 
    }, 
    draw: function() { 
     draw_legend() 
     draw_plot() 
    } 
    } 
} 

Niektórzy ludzie opowiadają testowania tylko interfejs publiczny swoimi klasami, co ma sens, ale ja Naprawdę lubię wchodzić w niektóre testy, aby przetestować każdy z komponentów osobno. Jeśli zepsuje moją funkcję draw_legend(), chciałbym, aby ten test się nie powiódł, a nie test dla publicznej funkcji draw(). Czy jestem tutaj na niewłaściwym torze?

Potrafię oddzielić każdy z komponentów w różnych klasach, na przykład utworzyć klasę Legend. Ale wydaje się głupie stworzenie klasy, która czasami jest tylko 5-10 liniami kodu, i byłoby to brzydsze, ponieważ musiałbym przekazać kilka prywatnych stanów. I nie byłbym w stanie przetestować funkcji pomocnika. Czy mimo to powinienem to zrobić? Czy powinienem to wyssać i przetestować tylko publiczny remis()? Czy jest jakieś inne rozwiązanie?

+0

Może to być pomocne [Jak testowanej jednostki prywatne w JavaScript] (http://philipwalton.com/articles/how-to-unit-test-private-functions-in-javascript/) – amirnissim

Odpowiedz

9

Nie ma możliwości uzyskania dostępu do funkcji wewnętrznych (prywatnych) z zewnętrznego zakresu. Jeśli chcesz przetestować funkcje wewnętrzne, możesz rozważyć dodanie publicznej metody tylko do celów testowych. Jeśli używasz jakiegoś środowiska kompilacji, na przykład ant, możesz wstępnie przetworzyć plik javascript do produkcji i usunąć te funkcje testowe.

W rzeczywistości Javascript jest językiem zorientowanym na obiekt. To po prostu nie jest typowane statycznie.

+5

W rzeczywistości JavaScript nie jest zorientowany obiektowo, jest oparty na prototypach. Po prostu może naśladować zachowanie OO. – pcjuzer

+11

@pcjuzer, JavaScript zdecydowanie jest zorientowany obiektowo, jest po prostu zaimplementowany inaczej niż klasyczne języki OO znane większości ludzi. –

+0

Jak dodać publiczną metodę testu bez utraty wszystkich zabezpieczeń? –

0

W języku zorientowanym obiektowo, zwykle testujemy jednostkowe metody chronione przed odziedziczeniem klasy, którą testują.

Oczywiście JavaScript nie jest tak naprawdę językiem obiektowym, a ten wzór nie pozwala na dziedziczenie.

Sądzę, że trzeba upublicznić swoje metody lub zrezygnować z ich testowania.

+0

W języku C# pochodne klasy nie mogą uzyskać dostępu do prywatnych członków swojej klasy bazowej. Czy to różni się od innych języków? –

+0

Również w Javie do prywatnych podklas nie można uzyskać dostępu do prywatnego elementu lub metody. –

+0

Przepraszam, miałem na myśli ochronę. –

1

W rzeczywistości istnieje łatwy sposób. Możesz użyć ajaxa do załadowania skryptu i wstrzyknięcia funkcji, która eksponuje prywatne funkcje. Mam przykład here, który używa qUnit i jQuery. Ale jestem pewien, że to samo można łatwo osiągnąć za pomocą czystej JavaScript.

+0

Jest to problem, jeśli chcesz przetestować zestaw wersji skompilowanej (lub uciążliwej, itp.). Testuję tylko wersję skompilowaną - jeśli jest problem z kompilacją, muszę to wiedzieć. –

3

Mam podobny problem. Rozwiązanie, które wymyśliłem, nie jest czymś, co lubię, ale wykonuje to zadanie i nie ma lepszego rozwiązania, jakie mogę znaleźć.

function Graph() 
{ 
    this.Test = function _Test(expressionStr) { return eval(expressionStr); } 

    var private_data; 
    function draw_legend() { ... } 
    function draw_plot() { ... } 
    function helper_func() { ... } 
    ... 
} 

przetestować:

var g = new Graph(); 
g.Test("helper_func()") == something; 
g.Test("private_data") == something2 
5

Moje rozwiązanie jest tylko trochę hack.QUnit przykład:

Na szczycie Qunit testu html Mam oświadczył:

var TEST_AVAILABLE = true; 

W sprawdzalne klasie mam fragment takiego:

if(TEST_AVAILABLE){ 
    this.test={ 
     hasDraft:hasDraft, 
     isInterpIdIn:isInterpIdIn, 
     // other private methods 
    }; 
} 

W QUnit można zweryfikować

test("hello booth", function() { 
    var b = new Booth(); 
    ok(b); 
    ok(b.test); 
    ok(!b.test.hasDraft()); 
}); 
+0

podobny do sugestii tutaj http://www.mikeball.us/blog/how-to-make-testable-private-functions-in-javascript – jlarson

+0

@jlarson url wydaje się, że zmienił się na http://www.mikeball.us/blog/testable-private-methods-in-javascript / –

0

Jest tylko jedna odpowiednia opcja: Różne konstrukcje dla Te Sting i produkcyjne tylko

1) rozwój znak części

/* test-code */ 
api._foo = foo 
/* end-test-code */ 

2) pozbawić je później ...;)

grunt.registerTask("deploy", 
    [ 
    "concat", 
    "strip-code", 
    ... 

@philwalton napisał piękne artykuły:

Powiązane problemy