2014-06-22 63 views
2

我已經開始重構我的代碼以使其可測試。我發現問題的一個領域是將對象構造和應用程序邏輯混合在一起。如果我有一個名爲SomeClass構造函數執行應用邏輯也實例化另一個I類運行中的問題時,我嘗試測試:將對象構造與應用程序邏輯混合

function SomeClass() { 

    //does lots of application type work 
    //but then also instantiates a different object 
    new AnotherClass(); 
} 

測試變得困難,因爲現在我需要找到一種方法來創建在AnotherClass測試環境。

我已經處理了使用依賴注入的這個問題。所以SomeClass需要的AnotherClass實例作爲參數:

function SomeClass(anotherObj) { 

} 

問題的,這是因爲據我可以看到的是這一切都爲推遲問題在我的應用程序別的地方。我仍然需要在我的代碼中的其他地方從AnotherClass創建anotherObj

這谷歌測試文章http://googletesting.blogspot.co.uk/2008/08/by-miko-hevery-so-you-decided-to.html建議:

爲了有一個可測試的代碼庫您的應用程序應該有兩個 種類別。這些工廠都有「新」運營商 ,它們負責構建應用程序的對象圖, ,但不做任何事情。而且應用程序邏輯類沒有「新」運算符並負責做工作。

這聽起來完全像我的問題,工廠類型模式是我所需要的。所以,我想是這樣的:

function anotherClassFactory() { 
    return new AnotherClass(); 
} 

function SomeClass() { 
    anotherClassFactory(); 
} 

但隨後SomeClass還是對工廠的依賴。我如何正確解決這個問題?

回答

1

(我在做這個社區維基答案,因爲坦白說,我覺得它只是回答了這個問題的一部分,而留下太多的說出來,希望別人更多的知識,可以提高它。)

SomeClass仍然依賴於工廠。我如何正確解決這個問題?

根據this article由你鏈接的一個鏈接,你做這樣的:

anotherclass.js

function AnotherClass() { 
} 
AnotherClass.prototype.foo = function() { /* ... */ }; 
AnotherClass.prototype.bar = function() { /* ... */ }; 
AnotherClass.prototype.baz = function() { /* ... */ }; 

someclass.js

function SomeClass(a) { 
    // ...app logic... 

    // Use AnotherClass instance `a`; let's say you're going to call `foo`, 
    // but have no use for `bar` or `baz` 
    a.foo(); 

    // ...app logic... 
} 

someclass-test.js

function someClass_testSomething() { 
    var sc = new SomeClass({ 
     foo: function() { /* ...appropriate `foo` code for this test... */} 
    }); 
    // ...test `sc`... 
} 
function someClass_testSomethingElse() { 
    // ... 
} 

app.js

function buildApp() { 
    return { 
     // ...lots of various things, including: 
     sc: new SomeClass(new AnotherClass()) 
    }; 
} 

所以真正的應用程序使用buildApp,這給SomeClassAnotherClass例如建。您對SomeClass的測試將使用someClass_testSomething等,它使用真實的SomeClass而不是真實的SomeClass,而不是包含的真實AnotherClass,它僅用於測試目的而言是

我的依賴注入的富較弱,不過,老實說,我不知道怎樣buildApp擴展到現實世界中,也沒有我看你應該做的,如果有方法來創建一個什麼反對做的工作,如:

SomeClass.prototype.doSomething = function() { 
    // Here, I need an instance of AnotherClass; maybe I even need to 
    // create a variable number of them, depending on logic internal 
    // to the method. 
}; 

你不是要通過一切方法需要作爲參數,這將是一個噩夢般的意大利麪條。這可能是爲什麼更多的靜態語言,通常有工具,而不是隻涉及編碼模式。


在JavaScript中,當然,我們還有另外一個選擇:只要繼續下去,並在代碼中使用new AnotherClass

anotherclass.js

function AnotherClass() { 
} 
AnotherClass.prototype.foo = function() { /* ... */ }; 
AnotherClass.prototype.bar = function() { /* ... */ }; 
AnotherClass.prototype.baz = function() { /* ... */ }; 

someclass.js

function SomeClass() { 
    // ...app logic... 

    // Use AnotherClass instance `a`; let's say you're going to call `foo`, 
    // but have no use for `bar` or `baz` 
    (new AnotherClass()).foo(); 

    // ...app logic... 
} 

someclass-test.js

var AnotherClass; 
function someClass_testSomething() { 
    // Just enough AnotherClass for this specific test; there might be others 
    // for other tests 
    AnotherClass = function() { 
    }; 
    AnotherClass.prototype.foo = function() { /* ...appropriate `foo` code for this test... */}; 

    var sc = new SomeClass(); 
    // ...test `sc`... 
} 
function someClass_testSomethingElse() { 
    // ... 
} 

你在你的真正的應用程序使用anotherclass.jssomeclass.js,你測試SomeClass時使用someclass.jssomeclass-test.js

這是一個粗略的草圖,當然;我假設你的真實世界的應用程序可能並沒有全局的全局(SomeClass,AnotherClass),但是它包含SomeClassAnotherClass也可能被用來包含SomeClass,並且包含測試爲它和他們的各種假冒AnotherClass s。

+1

感謝您的詳細解答。我讀過鏈接文章,我認爲你答案的第一部分解釋了爲什麼我沒有采取這種方法......在現實世界中,或者至少在現實世界中,當涉及到js時,我不會那樣做。目前我已經得到了你在答案的第二部分中提出的場景......這是模擬出一個假的AnotherClass。正如你所說的,希望有人能提出一個改進。 –