-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chapter 04: copy code from chapter 03 to the chapter 04 folder in ord…
…er to continue with the book
- Loading branch information
Showing
10 changed files
with
325 additions
and
0 deletions.
There are no files selected for viewing
3 changes: 3 additions & 0 deletions
3
chapter_04-interaction-testing-using-mock-objects/LogAn/ArgumentError.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
class ArgumentError extends Error {} | ||
|
||
module.exports = ArgumentError; |
15 changes: 15 additions & 0 deletions
15
chapter_04-interaction-testing-using-mock-objects/LogAn/alwaysValidFakeExtensionManager.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
function alwaysValidFakeExtensionManager() { | ||
/** | ||
* @param {string} fileName | ||
* @return {Promise} | ||
*/ | ||
async function isValid(fileName) { | ||
return true; | ||
} | ||
|
||
return { | ||
isValid, | ||
}; | ||
} | ||
|
||
module.exports = alwaysValidFakeExtensionManager; |
24 changes: 24 additions & 0 deletions
24
chapter_04-interaction-testing-using-mock-objects/LogAn/extensionManager.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
const fileExtensionManagerFactory = require('./fileExtensionManager'); | ||
|
||
function extensionManager() { | ||
let customManager = null; | ||
|
||
function create() { | ||
if (customManager !== null) { | ||
return customManager; | ||
} | ||
|
||
return fileExtensionManagerFactory(); | ||
} | ||
|
||
function setManager(manager) { | ||
customManager = manager; | ||
} | ||
|
||
return { | ||
create, | ||
setManager, | ||
}; | ||
} | ||
|
||
module.exports = extensionManager; |
26 changes: 26 additions & 0 deletions
26
chapter_04-interaction-testing-using-mock-objects/LogAn/fakeExtensionManager.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
function fakeExtensionManager() { | ||
/** | ||
* @type {boolean} | ||
*/ | ||
let valid = false; | ||
|
||
/** | ||
* @param {boolean} value | ||
*/ | ||
function willBeValid(value) { | ||
valid = value; | ||
} | ||
|
||
/** | ||
* @param {string} fileName | ||
*/ | ||
async function isValid(fileName) { | ||
return valid; | ||
} | ||
|
||
return { | ||
willBeValid, | ||
isValid, | ||
}; | ||
} | ||
module.exports = fakeExtensionManager; |
39 changes: 39 additions & 0 deletions
39
chapter_04-interaction-testing-using-mock-objects/LogAn/fileExtensionManager.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
const fs = require('fs'); | ||
const util = require('util'); | ||
|
||
const readFilePromisied = util.promisify(fs.readFile); | ||
|
||
function fileExtensionManager() { | ||
/** | ||
* @param {string} fileName | ||
* @return {Promise} | ||
*/ | ||
async function isValid(fileName) { | ||
const fileNameExtensions = await readFilePromisied( | ||
`${__dirname}/fileNameExtensions.config.json`, | ||
'utf8' | ||
).then(fileContent => JSON.parse(fileContent).extensions); | ||
|
||
const isValidExtension = fileNameExtensions.some( | ||
function checkFileNameExtension(extension) { | ||
if ( | ||
fileName | ||
.toUpperCase() | ||
.endsWith(`.${extension.toUpperCase()}`) | ||
) { | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
); | ||
|
||
return isValidExtension; | ||
} | ||
|
||
return { | ||
isValid, | ||
}; | ||
} | ||
|
||
module.exports = fileExtensionManager; |
3 changes: 3 additions & 0 deletions
3
chapter_04-interaction-testing-using-mock-objects/LogAn/fileNameExtensions.config.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"extensions": ["slf", "sql"] | ||
} |
47 changes: 47 additions & 0 deletions
47
chapter_04-interaction-testing-using-mock-objects/LogAn/logAnalyzer.class.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
const ArgumentError = require('./ArgumentError'); | ||
const fileExtensionManagerFactory = require('./fileExtensionManager'); | ||
|
||
class LogAnalyzer { | ||
constructor() { | ||
/** | ||
* @type {boolean} | ||
*/ | ||
this.wasLastFileNameValid = false; | ||
} | ||
/** | ||
* @return {boolean} | ||
*/ | ||
getWasLastFileNameValid() { | ||
return this.wasLastFileNameValid; | ||
} | ||
|
||
/** | ||
* a virtual function created to use "Extract and Override" technique | ||
*/ | ||
getManager() { | ||
return fileExtensionManagerFactory(); | ||
} | ||
|
||
/** | ||
* @param {string} fileName | ||
* @return {Promise} | ||
*/ | ||
async isValidLogFileName(fileName) { | ||
this.wasLastFileNameValid = false; | ||
|
||
if (fileName === '') { | ||
throw new ArgumentError('filename has to be provided'); | ||
} | ||
|
||
const result = await this.getManager().isValid(fileName); | ||
|
||
if (!result) { | ||
return false; | ||
} | ||
|
||
this.wasLastFileNameValid = true; | ||
return true; | ||
} | ||
} | ||
|
||
module.exports = LogAnalyzer; |
43 changes: 43 additions & 0 deletions
43
chapter_04-interaction-testing-using-mock-objects/LogAn/logAnalyzer.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
const ArgumentError = require('./ArgumentError'); | ||
|
||
function logAnalyzer(extensionManager) { | ||
/** | ||
* @type {boolean} | ||
*/ | ||
let wasLastFileNameValid; | ||
|
||
/** | ||
* @return {boolean} | ||
*/ | ||
function getWasLastFileNameValid() { | ||
return wasLastFileNameValid; | ||
} | ||
|
||
/** | ||
* @param {string} fileName | ||
* @return {Promise} | ||
*/ | ||
async function isValidLogFileName(fileName) { | ||
wasLastFileNameValid = false; | ||
|
||
if (fileName === '') { | ||
throw new ArgumentError('filename has to be provided'); | ||
} | ||
|
||
const result = await extensionManager.isValid(fileName); | ||
|
||
if (!result) { | ||
return false; | ||
} | ||
|
||
wasLastFileNameValid = true; | ||
return true; | ||
} | ||
|
||
return { | ||
getWasLastFileNameValid, | ||
isValidLogFileName, | ||
}; | ||
} | ||
|
||
module.exports = logAnalyzer; |
111 changes: 111 additions & 0 deletions
111
chapter_04-interaction-testing-using-mock-objects/LogAn/logAnalyzer.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
const logAnalyzerFactory = require('./logAnalyzer'); | ||
const fakeExtensionManagerFactory = require('./fakeExtensionManager'); | ||
const extensionManagerFactory = require('./extensionManager'); | ||
|
||
// imported to try the technique "Extract and override" | ||
const TestableLogAnalyzerClass = require('./testableLogAnalyzer.class'); | ||
|
||
let myFakeExtensionManager; | ||
|
||
beforeEach(() => { | ||
myFakeExtensionManager = fakeExtensionManagerFactory(); | ||
}); | ||
|
||
describe.each([ | ||
['johndoe.js', false], | ||
['johndoe.slf', true], | ||
['johndoe.SLF', true], | ||
])('isValidLogFileName("%s"))', (fileName, expected) => { | ||
it(`bad extension returns ${expected}`, async () => { | ||
myFakeExtensionManager.willBeValid(expected); | ||
|
||
const logAnalyzer = logAnalyzerFactory(myFakeExtensionManager); | ||
const result = await logAnalyzer.isValidLogFileName(fileName); | ||
expect(result).toBe(expected); | ||
}); | ||
}); | ||
|
||
describe('isValidLogFileName', () => { | ||
it('empty filename throws error', async () => { | ||
async function emptyLogFileName() { | ||
const logAnalyzer = logAnalyzerFactory(myFakeExtensionManager); | ||
|
||
return logAnalyzer.isValidLogFileName(''); | ||
} | ||
|
||
await expect(emptyLogFileName()).rejects.toThrow( | ||
'filename has to be provided' | ||
); | ||
}); | ||
|
||
/** | ||
* an example of state-based testing | ||
*/ | ||
it.each` | ||
fileName | expected | ||
${'johndoe.foo'} | ${false} | ||
${'johndoe.slf'} | ${true} | ||
`( | ||
'when called there changes wasLastFileNameValid that returns $expected', | ||
async ({ fileName, expected }) => { | ||
myFakeExtensionManager.willBeValid(expected); | ||
|
||
const logAnalyzer = logAnalyzerFactory(myFakeExtensionManager); | ||
await logAnalyzer.isValidLogFileName(fileName); | ||
const result = logAnalyzer.getWasLastFileNameValid(); | ||
|
||
expect(result).toBe(expected); | ||
} | ||
); | ||
|
||
/** | ||
* an example of use of "injecting a fake just before a method call" | ||
* right now I'm not injecting a fake, and extensionManager is returning fileExtensionManager, | ||
* therefore this test is an integration test and not a unit test!!!! | ||
*/ | ||
it('return true using extensionManagerFactory', async () => { | ||
const extensionManager = extensionManagerFactory(); | ||
const logAnalyzer = logAnalyzerFactory(extensionManager.create()); | ||
const result = await logAnalyzer.isValidLogFileName('johndoe.sql'); | ||
|
||
expect(result).toBe(true); | ||
}); | ||
|
||
/** | ||
* an example of use of "injecting a fake just before a method call" | ||
* In this case I'm setting a fake extension manager, that converts this in a unit test!!, because | ||
* right now I have not external dependencies. | ||
*/ | ||
it('return true using extensionManagerFactory', async () => { | ||
myFakeExtensionManager.willBeValid(true); | ||
const extensionManager = extensionManagerFactory(); | ||
extensionManager.setManager(myFakeExtensionManager); | ||
|
||
const logAnalyzer = logAnalyzerFactory(extensionManager.create()); | ||
const result = await logAnalyzer.isValidLogFileName('johndoe.sql'); | ||
|
||
expect(result).toBe(true); | ||
}); | ||
|
||
/** | ||
* I'm using the tecnique "Extract and override", this technique has several steps: | ||
* | ||
* step 1: create a virtual function in the unit under test(logAnalyzer.js in this case) | ||
* that returns the real extension manager, the one that works with the filesystem | ||
* | ||
* step 2: create a class that extends of it | ||
* | ||
* step3: use this new class to create the tests!! :) | ||
*/ | ||
it('return false using testableLogAnalyzer', async () => { | ||
const expected = false; | ||
myFakeExtensionManager.willBeValid(expected); | ||
|
||
const logAnalyzer = new TestableLogAnalyzerClass( | ||
myFakeExtensionManager | ||
); | ||
const result = await logAnalyzer.isValidLogFileName('johndoe.ts'); | ||
|
||
expect(result).toBe(expected); | ||
}); | ||
}); |
14 changes: 14 additions & 0 deletions
14
chapter_04-interaction-testing-using-mock-objects/LogAn/testableLogAnalyzer.class.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
const fakeExtensionManagerFactory = require('./fakeExtensionManager'); | ||
const logAnalizer = require('./logAnalyzer.class'); | ||
|
||
class TestableLogAnalyzer extends logAnalizer { | ||
constructor(extensionManager) { | ||
super(); | ||
this.manager = extensionManager; | ||
} | ||
getManager() { | ||
return this.manager; | ||
} | ||
} | ||
|
||
module.exports = TestableLogAnalyzer; |