From ce9638653984071597fae565ea336abbbe1bde0f Mon Sep 17 00:00:00 2001 From: martintl25 Date: Tue, 12 Mar 2024 15:31:34 +0800 Subject: [PATCH 1/7] Stub failed: Mocking methods leave the app.people empty --- lab2/main_test.js | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/lab2/main_test.js b/lab2/main_test.js index 5034468e..6df1f05d 100644 --- a/lab2/main_test.js +++ b/lab2/main_test.js @@ -1,6 +1,43 @@ const test = require('node:test'); const assert = require('assert'); +const fs = require('fs'); +// Stub Failed: Leave Application.people empty +// test.mock.method(fs, 'readFile', (a, b) =>'Amy\nBenson\nCharlie'); +// test.mock.method(util, 'promisify', (a) => a); const { Application, MailSystem } = require('./main'); +// Alternative +function init_test(testcase) { + if (!testcase instanceof Array) { + return -1; + } + text = testcase.toString().replace(/,/g, "\n"); + try { + fs.writeFileSync("name_list.txt", text, "utf-8"); + } catch (error) { + console.log(error); + return -1; + } + return 0; +} + // TODO: write your tests here -// Remember to use Stub, Mock, and Spy when necessary \ No newline at end of file +// Remember to use Stub, Mock, and Spy when necessary + +test("Test MailSystem's write", (t) => { +}); + +test("Test MailSystem's send", (t) => { +}); + +test("Test Application's getNames", (t) => { +}); + +test("Test Application's getRandomPerson", (t) => { +}); + +test("Test Application's selectNextPerson", (t) => { +}); + +test("Test Application's notifySelected", (t) => { +}); \ No newline at end of file From 9b172ab8402df00382964ac58fb1f387937d0242 Mon Sep 17 00:00:00 2001 From: martintl25 Date: Tue, 12 Mar 2024 15:38:42 +0800 Subject: [PATCH 2/7] Complete the MailSystem testing --- lab2/main_test.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lab2/main_test.js b/lab2/main_test.js index 6df1f05d..db6c9ba4 100644 --- a/lab2/main_test.js +++ b/lab2/main_test.js @@ -25,9 +25,27 @@ function init_test(testcase) { // Remember to use Stub, Mock, and Spy when necessary test("Test MailSystem's write", (t) => { + const mailSys = new MailSystem(); + // 1. test return type + assert.strictEqual(typeof mailSys.write("Amy"), "string"); + // 2. validate legality of context returned + assert.strictEqual(mailSys.write("Amy"), "Congrats, Amy!"); }); test("Test MailSystem's send", (t) => { + const mailSys = new MailSystem(); + // 1. test return type + assert.strictEqual(typeof mailSys.send("testing", "random test"), "boolean"); + var success = false, failure = false; + for(let i = 0; i < 10; i++) { + if (mailSys.send("testing", "random test")) { + success = true; + } else { + failure = true; + } + } + // 2. check if the sys + assert(success && failure); }); test("Test Application's getNames", (t) => { From 4da6efedce8893c62aa723bcf212846d58d3f90f Mon Sep 17 00:00:00 2001 From: martintl25 Date: Tue, 12 Mar 2024 16:08:20 +0800 Subject: [PATCH 3/7] Test MailSystem's send with mocking Math.random() --- lab2/main_test.js | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/lab2/main_test.js b/lab2/main_test.js index db6c9ba4..08a58ade 100644 --- a/lab2/main_test.js +++ b/lab2/main_test.js @@ -2,11 +2,12 @@ const test = require('node:test'); const assert = require('assert'); const fs = require('fs'); // Stub Failed: Leave Application.people empty -// test.mock.method(fs, 'readFile', (a, b) =>'Amy\nBenson\nCharlie'); +test.mock.method(fs, 'readFile', (a, b) =>'Amy\nBenson\nCharlie'); // test.mock.method(util, 'promisify', (a) => a); const { Application, MailSystem } = require('./main'); -// Alternative +// Alternative of Stub: Write File +/* function init_test(testcase) { if (!testcase instanceof Array) { return -1; @@ -20,11 +21,12 @@ function init_test(testcase) { } return 0; } +*/ // TODO: write your tests here // Remember to use Stub, Mock, and Spy when necessary -test("Test MailSystem's write", (t) => { +test("Test MailSystem's write", () => { const mailSys = new MailSystem(); // 1. test return type assert.strictEqual(typeof mailSys.write("Amy"), "string"); @@ -36,16 +38,15 @@ test("Test MailSystem's send", (t) => { const mailSys = new MailSystem(); // 1. test return type assert.strictEqual(typeof mailSys.send("testing", "random test"), "boolean"); - var success = false, failure = false; - for(let i = 0; i < 10; i++) { - if (mailSys.send("testing", "random test")) { - success = true; - } else { - failure = true; - } + // 2. Asume that Math.random() works, check if the function provide a valid output + t.mock.method(Math, "random", () => 1.0); + for(let i = 0; i < 5; i++) { + assert.strictEqual(mailSys.send("testing", "random test"), true); + } + t.mock.method(Math, "random", () => 0.0); + for(let i = 0; i < 5; i++) { + assert.strictEqual(mailSys.send("testing", "random test"), false); } - // 2. check if the sys - assert(success && failure); }); test("Test Application's getNames", (t) => { From db91fb999bfe1d26189bdda555026c1c2c686980 Mon Sep 17 00:00:00 2001 From: martintl25 Date: Tue, 12 Mar 2024 16:38:28 +0800 Subject: [PATCH 4/7] Stub Success: pass if define the testing function as asynchronus and await Application instance's getNames --- lab2/main_test.js | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/lab2/main_test.js b/lab2/main_test.js index 08a58ade..e21839da 100644 --- a/lab2/main_test.js +++ b/lab2/main_test.js @@ -1,27 +1,18 @@ const test = require('node:test'); const assert = require('assert'); const fs = require('fs'); -// Stub Failed: Leave Application.people empty -test.mock.method(fs, 'readFile', (a, b) =>'Amy\nBenson\nCharlie'); -// test.mock.method(util, 'promisify', (a) => a); +test.mock.method(fs, 'readFile', (a, b, callback) => callback(null, "Amy\nBenson\nCharlie")); const { Application, MailSystem } = require('./main'); // Alternative of Stub: Write File -/* -function init_test(testcase) { +async function init_test(testcase) { if (!testcase instanceof Array) { return -1; } text = testcase.toString().replace(/,/g, "\n"); - try { - fs.writeFileSync("name_list.txt", text, "utf-8"); - } catch (error) { - console.log(error); - return -1; - } + await writeFile("name_list.txt", test, "utf-8"); return 0; } -*/ // TODO: write your tests here // Remember to use Stub, Mock, and Spy when necessary @@ -49,7 +40,11 @@ test("Test MailSystem's send", (t) => { } }); -test("Test Application's getNames", (t) => { +test("Test Application's getNames", async () => { + const app = new Application(); + const [people, selected] = await app.getNames(); + assert.deepStrictEqual(people, ['Amy', 'Benson', 'Charlie']); + assert.deepStrictEqual(selected, []); }); test("Test Application's getRandomPerson", (t) => { From 43d8e383cc23689529a0965d72b8a5ca28c94ac9 Mon Sep 17 00:00:00 2001 From: martintl25 Date: Tue, 12 Mar 2024 18:10:33 +0800 Subject: [PATCH 5/7] Complete testing code of Application's getRandomPerson and selectNextPerson --- lab2/main_test.js | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/lab2/main_test.js b/lab2/main_test.js index e21839da..bc7ec491 100644 --- a/lab2/main_test.js +++ b/lab2/main_test.js @@ -29,18 +29,19 @@ test("Test MailSystem's send", (t) => { const mailSys = new MailSystem(); // 1. test return type assert.strictEqual(typeof mailSys.send("testing", "random test"), "boolean"); - // 2. Asume that Math.random() works, check if the function provide a valid output - t.mock.method(Math, "random", () => 1.0); + // 2. Asume that Math.random() works, check if the function provide a valid output (spy?) + t.mock.method(Math, "random", () => 1.0, { times: 5 }); for(let i = 0; i < 5; i++) { assert.strictEqual(mailSys.send("testing", "random test"), true); } - t.mock.method(Math, "random", () => 0.0); + t.mock.method(Math, "random", () => 0.0, { times: 5 }); for(let i = 0; i < 5; i++) { assert.strictEqual(mailSys.send("testing", "random test"), false); } }); test("Test Application's getNames", async () => { + // Stub? const app = new Application(); const [people, selected] = await app.getNames(); assert.deepStrictEqual(people, ['Amy', 'Benson', 'Charlie']); @@ -48,10 +49,43 @@ test("Test Application's getNames", async () => { }); test("Test Application's getRandomPerson", (t) => { + const app = new Application(); + testcase = ['Amy', 'Benson', 'Charlie']; + app.people = testcase;// Stub + // Spy on output + t.mock.method(Math, "random", () => 0.3, { times: 1 }); + assert.strictEqual(app.getRandomPerson(), "Amy"); + t.mock.method(Math, "random", () => 0.6, { times: 1 }); + assert.strictEqual(app.getRandomPerson(), "Benson"); + t.mock.method(Math, "random", () => 0.9, { times: 1 }); + assert.strictEqual(app.getRandomPerson(), "Charlie"); + t.mock.method(Math, "floor", (_) => 0, { times: 1 }); + assert.strictEqual(app.getRandomPerson(), "Amy"); + t.mock.method(Math, "floor", (_) => 1, { times: 1 }); + assert.strictEqual(app.getRandomPerson(), "Benson"); + t.mock.method(Math, "floor", (_) => 2, { times: 1 }); + assert.strictEqual(app.getRandomPerson(), "Charlie"); }); test("Test Application's selectNextPerson", (t) => { + const app = new Application(); + testcase = ['Amy', 'Benson', 'Charlie']; + app.people = testcase;// Stub + assert(app.people.includes(app.selectNextPerson())); + //app.getRandomPerson = t.mock.fn(app.getRandomPerson, ()=>app.selected[0], {times:2}); + const proxy = t.mock.method(app, "getRandomPerson", ()=>app.selected[0], { times: 5 }); + assert(app.people.includes(app.selectNextPerson())); + assert.strictEqual(proxy.mock.calls.length, 5);// call the selected person for five times + for (let i = 0; i < 5; i++) { + assert.strictEqual(proxy.mock.calls[i].result, app.selected[0]); + } + assert(app.people.includes(app.selectNextPerson())); + assert.deepStrictEqual(app.people.toSorted(), app.selected.toSorted()); + assert.strictEqual(app.selectNextPerson(), null); }); test("Test Application's notifySelected", (t) => { + // Mock cross-platform API + // app.mailSystem.write = test.mock.fn(app.mailSystem.write); + // app.mailSystem.send = test.mock.fn(app.mailSystem.send); }); \ No newline at end of file From be52f0e994f560dfe4b54de01cbf17b7d7d227cf Mon Sep 17 00:00:00 2001 From: martintl25 Date: Tue, 12 Mar 2024 18:36:42 +0800 Subject: [PATCH 6/7] Complete the code for testing `main.js`. And, remove `TODO` tag --- lab2/main_test.js | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/lab2/main_test.js b/lab2/main_test.js index bc7ec491..b5a9b956 100644 --- a/lab2/main_test.js +++ b/lab2/main_test.js @@ -5,14 +5,14 @@ test.mock.method(fs, 'readFile', (a, b, callback) => callback(null, "Amy\nBenson const { Application, MailSystem } = require('./main'); // Alternative of Stub: Write File -async function init_test(testcase) { - if (!testcase instanceof Array) { - return -1; - } - text = testcase.toString().replace(/,/g, "\n"); - await writeFile("name_list.txt", test, "utf-8"); - return 0; -} +// async function init_test(testcase) { +// if (!testcase instanceof Array) { +// return -1; +// } +// text = testcase.toString().replace(/,/g, "\n"); +// await writeFile("name_list.txt", test, "utf-8"); +// return 0; +// } // TODO: write your tests here // Remember to use Stub, Mock, and Spy when necessary @@ -72,13 +72,15 @@ test("Test Application's selectNextPerson", (t) => { testcase = ['Amy', 'Benson', 'Charlie']; app.people = testcase;// Stub assert(app.people.includes(app.selectNextPerson())); - //app.getRandomPerson = t.mock.fn(app.getRandomPerson, ()=>app.selected[0], {times:2}); + + // Mock Implementation: call the selected person for five times const proxy = t.mock.method(app, "getRandomPerson", ()=>app.selected[0], { times: 5 }); assert(app.people.includes(app.selectNextPerson())); - assert.strictEqual(proxy.mock.calls.length, 5);// call the selected person for five times + assert.strictEqual(proxy.mock.calls.length, 5); for (let i = 0; i < 5; i++) { assert.strictEqual(proxy.mock.calls[i].result, app.selected[0]); } + assert(app.people.includes(app.selectNextPerson())); assert.deepStrictEqual(app.people.toSorted(), app.selected.toSorted()); assert.strictEqual(app.selectNextPerson(), null); @@ -86,6 +88,25 @@ test("Test Application's selectNextPerson", (t) => { test("Test Application's notifySelected", (t) => { // Mock cross-platform API - // app.mailSystem.write = test.mock.fn(app.mailSystem.write); - // app.mailSystem.send = test.mock.fn(app.mailSystem.send); + const app = new Application(); + + // Stub + testcase = ['Amy', 'Benson', 'Charlie']; + app.people = testcase; + app.selected = testcase; + + const ms_write = test.mock.method(app.mailSystem, "write"); + const ms_send = test.mock.method(app.mailSystem, "send"); + + app.notifySelected(); + + assert.strictEqual(ms_write.mock.calls.length, app.selected.length); + assert.strictEqual(ms_send.mock.calls.length, app.selected.length); + + for (let i = 0; i < app.selected.length; i++) { + assert.strictEqual(ms_write.mock.calls[i].result, 'Congrats, ' + app.selected[i] + '!'); + assert.strictEqual(ms_write.mock.calls[i].result, ms_send.mock.calls[i].arguments[1]); + assert.strictEqual(ms_send.mock.calls[i].arguments[0], ms_send.mock.calls[i].arguments[0]); + } + }); \ No newline at end of file From d521004d5f487b531d26edaa46fff5fd73b2caba Mon Sep 17 00:00:00 2001 From: martintl25 Date: Tue, 12 Mar 2024 18:51:18 +0800 Subject: [PATCH 7/7] Finalized: Remove redundant code and Revise all the comments. --- lab2/main_test.js | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/lab2/main_test.js b/lab2/main_test.js index b5a9b956..6d8fb3f8 100644 --- a/lab2/main_test.js +++ b/lab2/main_test.js @@ -4,19 +4,7 @@ const fs = require('fs'); test.mock.method(fs, 'readFile', (a, b, callback) => callback(null, "Amy\nBenson\nCharlie")); const { Application, MailSystem } = require('./main'); -// Alternative of Stub: Write File -// async function init_test(testcase) { -// if (!testcase instanceof Array) { -// return -1; -// } -// text = testcase.toString().replace(/,/g, "\n"); -// await writeFile("name_list.txt", test, "utf-8"); -// return 0; -// } - -// TODO: write your tests here // Remember to use Stub, Mock, and Spy when necessary - test("Test MailSystem's write", () => { const mailSys = new MailSystem(); // 1. test return type @@ -29,7 +17,7 @@ test("Test MailSystem's send", (t) => { const mailSys = new MailSystem(); // 1. test return type assert.strictEqual(typeof mailSys.send("testing", "random test"), "boolean"); - // 2. Asume that Math.random() works, check if the function provide a valid output (spy?) + // 2. Asume that Math.random() works, check if the tested function provide a valid output (spy?) t.mock.method(Math, "random", () => 1.0, { times: 5 }); for(let i = 0; i < 5; i++) { assert.strictEqual(mailSys.send("testing", "random test"), true); @@ -41,7 +29,8 @@ test("Test MailSystem's send", (t) => { }); test("Test Application's getNames", async () => { - // Stub? + // Stub inputs via mocking fs.writeFile + // Assume fs.writeFile works functionally, the tested function would have a correct behaviour. const app = new Application(); const [people, selected] = await app.getNames(); assert.deepStrictEqual(people, ['Amy', 'Benson', 'Charlie']); @@ -50,15 +39,17 @@ test("Test Application's getNames", async () => { test("Test Application's getRandomPerson", (t) => { const app = new Application(); + // Stub testcase = ['Amy', 'Benson', 'Charlie']; - app.people = testcase;// Stub - // Spy on output + app.people = testcase; + // Spy on output via mocking Math.random() t.mock.method(Math, "random", () => 0.3, { times: 1 }); assert.strictEqual(app.getRandomPerson(), "Amy"); t.mock.method(Math, "random", () => 0.6, { times: 1 }); assert.strictEqual(app.getRandomPerson(), "Benson"); t.mock.method(Math, "random", () => 0.9, { times: 1 }); assert.strictEqual(app.getRandomPerson(), "Charlie"); + // Spy on output via mocking Math.floor() t.mock.method(Math, "floor", (_) => 0, { times: 1 }); assert.strictEqual(app.getRandomPerson(), "Amy"); t.mock.method(Math, "floor", (_) => 1, { times: 1 }); @@ -69,10 +60,10 @@ test("Test Application's getRandomPerson", (t) => { test("Test Application's selectNextPerson", (t) => { const app = new Application(); + //Stub testcase = ['Amy', 'Benson', 'Charlie']; - app.people = testcase;// Stub + app.people = testcase; assert(app.people.includes(app.selectNextPerson())); - // Mock Implementation: call the selected person for five times const proxy = t.mock.method(app, "getRandomPerson", ()=>app.selected[0], { times: 5 }); assert(app.people.includes(app.selectNextPerson())); @@ -80,33 +71,28 @@ test("Test Application's selectNextPerson", (t) => { for (let i = 0; i < 5; i++) { assert.strictEqual(proxy.mock.calls[i].result, app.selected[0]); } - + // All the people are selected assert(app.people.includes(app.selectNextPerson())); assert.deepStrictEqual(app.people.toSorted(), app.selected.toSorted()); assert.strictEqual(app.selectNextPerson(), null); }); test("Test Application's notifySelected", (t) => { - // Mock cross-platform API const app = new Application(); - // Stub testcase = ['Amy', 'Benson', 'Charlie']; app.people = testcase; app.selected = testcase; - + // Mock cross-platform API const ms_write = test.mock.method(app.mailSystem, "write"); const ms_send = test.mock.method(app.mailSystem, "send"); - + // Call tested function once and Examine info about function calls and data returned app.notifySelected(); - assert.strictEqual(ms_write.mock.calls.length, app.selected.length); assert.strictEqual(ms_send.mock.calls.length, app.selected.length); - for (let i = 0; i < app.selected.length; i++) { assert.strictEqual(ms_write.mock.calls[i].result, 'Congrats, ' + app.selected[i] + '!'); assert.strictEqual(ms_write.mock.calls[i].result, ms_send.mock.calls[i].arguments[1]); assert.strictEqual(ms_send.mock.calls[i].arguments[0], ms_send.mock.calls[i].arguments[0]); } - }); \ No newline at end of file