[英]How to test factory method in JS?
我在JS中有一個工廠方法,可以為我的node.js應用程序創建一個對象。 此工廠方法接收一些參數,我想測試是否正確創建了對象。
const LibX = require("libX");
const obj = deps => {
const { colorLib } = deps;
const hello = () => {
console.log(colorLib.sayHello()); // prints a phrase with cool colors
};
return {
hello
};
};
//Here I return `obj` with all dependencies included. Ready to use!
const objFactory = ({animal, owner = "max"}) => {
//For example,I need to know if phrase is being well constructed
const phrase = `${owner} from ${animal} says hello!`;
const lib = new LibX(phrase);
return obj({ colorLib: lib });
};
const myObj = objFactory({animal: "cat"});
myObj.hello();
obj
函數很容易測試,因為我將所有依賴項傳遞給對象,因此可以存根和監視所有想要的東西。
問題是objFactory
,該函數應該創建一個包含所有內容的obj
對象,為了做到這一點,我在那里使用了new LibX
,這意味着我無法模擬它。 我也無法測試該phrase
是否構建良好或是否正確傳遞。
這也違反了得墨 the 耳定律,因為我的工廠需要知道一些本不應該知道的東西。
如果不傳遞LibX
作為參數(這意味着我將需要一個Factory作為工廠....造成混淆了嗎?),我不知道如何解決此問題。
如何使objFactory
易於測試?
您需要問自己的第一個問題是您要測試什么。
您是否需要確保正確構建phrase
常量? 如果是這樣,則需要將其提取到單獨的函數並分別進行測試。
也許您想要的是測試myObj.hello();
的效果myObj.hello();
。 在這種情況下,我建議使hello()
返回一個字符串,而不是將其記錄到控制台。 這將使最終效果易於測試。
編寫清晰的代碼將避免產生不可模仿的依賴關系。 不能嘲笑您編寫示例的方法libx
(它是一個外部依賴項)。 或者我應該說,它不應該被嘲笑。 從技術上講,也可以對其進行模擬,但是我建議您不要這樣做,因為它會給圖片帶來其自身的復雜性。
這很簡單。 您的單元測試應該看起來像這樣:
it("should build the phrase correctly using all params", () => {
// given
const input = {animal: "dog", owner: "joe"};
// when
const result = buildPhrase(input);
// then
expect(result).to.equal("joe from dog says hello!");
});
it("should build the phrase correctly using only required params", () => {
// given
const input = {animal: "cat"};
// when
const result = buildPhrase(input);
// then
expect(result).to.equal("max from cat says hello!");
});
通過上面的單元測試,您的生產代碼將需要看起來像這樣:
const buildPhrase = function(input) {
const owner = input.owner || "max";
const animal = input.animal;
return `${owner} from ${animal} says hello!`;
};
在這里,短語構建已經過測試。 然后,您可以使用buildPhrase
你里面objFactory
。
這也很簡單。 您為工廠提供輸入,並期望輸出。 輸出將始終是輸入的函數,即相同的輸入將始終產生相同的輸出。 那么,如果可以預測預期的結果,為什么還要測試幕后情況呢?
it("should produce a function that returns correct greeting", () => {
// given
const input = {animal: "cat"};
const obj = objFactory(input);
// when
const result = obj.hello();
// then
expect(result).to.equal("max from cat says hello!");
});
最終可能會導致您進入以下生產代碼:
const LibX = require("libX");
const obj = deps => {
const { colorLib } = deps;
const hello = () => {
return colorLib.sayHello(); // note the change here
};
return {hello};
};
const objFactory = ({animal, owner = "max"}) => {
const phrase = `${owner} from ${animal} says hello!`;
const lib = new LibX(phrase);
return obj({ colorLib: lib });
};
require("libx")
的輸出 還是不。 如前所述,您實際上不應該這樣做。 不過,如果您被迫這樣做(我將推理留給了這個決定),則可以使用模擬需求或類似的工具。
const mock = require("mock-require");
let currentPhrase;
mock("libx", function(phrase) {
currentPhrase = phrase;
this.sayHello = function() {};
});
const objFactory = require("./objFactory");
describe("objFactory", () => {
it("should pass correct phrase to libx", () => {
// given
const input = {animal: "cat"};
// when
objFactory(input);
// then
expect(currentPhrase).to.be("max from cat says hello!");
});
});
但是請記住,這種方法比看起來復雜。 模擬require
依賴項覆蓋了require
的緩存,因此您必須記住清除它,以防萬一有其他不希望依賴項被嘲笑而是依賴於它執行操作的測試。 另外,您必須始終保持警惕,並確保代碼的執行順序(並不總是那么明顯)是正確的。 您必須先模擬依賴項,然后使用require()
,但是要確保這一點並不總是那么容易。
模擬依賴項的最簡單方法是始終注入它。 由於在代碼中使用了new
,因此將其包裝在一個可以隨時模擬的簡單函數中可能是有意義的:
const makeLibx = (phrase) => {
return new LibX(phrase);
};
如果您隨后將其注入到工廠中,則嘲笑將變得微不足道:
it("should pass correct input to libx", () => {
// given
let phrase;
const mockMakeLibx = function(_phrase) {
phrase = _phrase;
return {sayHello() {}};
};
const input = {animal: "cat"};
// when
objFactory(mockMakeLibx, input);
// then
expect(phrase).to.equal("max from cat says hello!");
});
顯然,這將導致您編寫如下內容:
const objFactory = (makeLibx, {animal, owner = "max"}) => {
const phrase = `${owner} from ${animal} says hello!`;
const lib = makeLibx(phrase);
return obj({ colorLib: lib });
};
我的最后一條建議是:始終提前計划代碼,並盡可能使用TDD。 如果您編寫生產代碼然后考慮如何進行測試,就會發現自己一遍又一遍地問同樣的問題:我該如何測試它? 我該如何模擬這種依賴性? 這不違反得墨meter耳定律嗎?
雖然您應該問自己的問題是:我希望這段代碼做什么? 我要如何表現? 它的效果應該是什么樣的?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.