From ed4b23e03fea2b1d37d0d3de2fced42123cfd1db Mon Sep 17 00:00:00 2001 From: i0natan Date: Sun, 7 Apr 2019 12:54:47 +0300 Subject: [PATCH 1/3] Bullet 4.4 - add data per test --- README.md | 21 ++++++++-- .../avoid-global-test-fixture.md | 42 +++++++++++++++++++ 2 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 sections/testingandquality/avoid-global-test-fixture.md diff --git a/README.md b/README.md index 0a17c343..f70ed660 100644 --- a/README.md +++ b/README.md @@ -440,16 +440,18 @@ All statements above will return false if used with `===`

-## ![✔] 4.4 Carefully choose your CI platform (Jenkins vs CircleCI vs Travis vs Rest of the world) +## ![✔] 4.4 Avoid global test fixtures and seeds, add data per-test -**TL;DR:** Your continuous integration platform (CICD) will host all the quality tools (e.g test, lint) so it should come with a vibrant ecosystem of plugins. [Jenkins](https://jenkins.io/) used to be the default for many projects as it has the biggest community along with a very powerful platform at the price of complex setup that demands a steep learning curve. Nowadays, it has become much easier to set up a CI solution using SaaS tools like [CircleCI](https://circleci.com) and others. These tools allow crafting a flexible CI pipeline without the burden of managing the whole infrastructure. Eventually, it's a trade-off between robustness and speed - choose your side carefully +**TL;DR:** To prevent tests coupling and easily reason about the test flow, each test should add and act on its own set of DB rows. Whenever a test need to pull or assume the existence of some DB data - it must explicitly add that data and avoid mutating any other records -**Otherwise:** Choosing some niche vendor might get you blocked once you need some advanced customization. On the other hand, going with Jenkins might burn precious time on infrastructure setup +**Otherwise:** Consider a scenario where deployment is aborted due to failing tests, team is now going to spend precious investigation time , do we have a bug? oh no —, it seems that two tests were mutating the same seed data -🔗 [**Read More: Choosing CI platform**](/sections/testingandquality/citools.md) +🔗 [**Read More: Avoid global test fixtures**](/sections/testingandquality/avoid-global-test-fixture.md)

+ + ## ![✔] 4.5 Constantly inspect for vulnerable dependencies **TL;DR:** Even the most reputable dependencies such as Express have known vulnerabilities. This can get easily tamed using community and commercial tools such as 🔗 [npm audit](https://docs.npmjs.com/cli/audit) and 🔗 [snyk.io](https://snyk.io) that can be invoked from your CI on every build @@ -498,8 +500,19 @@ All statements above will return false if used with `===` 🔗 [**Read More: Refactoring!**](/sections/testingandquality/refactoring.md) +

+ +## ![✔] 4.11 Carefully choose your CI platform (Jenkins vs CircleCI vs Travis vs Rest of the world) + +**TL;DR:** Your continuous integration platform (CICD) will host all the quality tools (e.g test, lint) so it should come with a vibrant ecosystem of plugins. [Jenkins](https://jenkins.io/) used to be the default for many projects as it has the biggest community along with a very powerful platform at the price of complex setup that demands a steep learning curve. Nowadays, it has become much easier to set up a CI solution using SaaS tools like [CircleCI](https://circleci.com) and others. These tools allow crafting a flexible CI pipeline without the burden of managing the whole infrastructure. Eventually, it's a trade-off between robustness and speed - choose your side carefully + +**Otherwise:** Choosing some niche vendor might get you blocked once you need some advanced customization. On the other hand, going with Jenkins might burn precious time on infrastructure setup + +🔗 [**Read More: Choosing CI platform**](/sections/testingandquality/citools.md) +


+

⬆ Return to top

# `5. Going To Production Practices` diff --git a/sections/testingandquality/avoid-global-test-fixture.md b/sections/testingandquality/avoid-global-test-fixture.md new file mode 100644 index 00000000..54fa0acc --- /dev/null +++ b/sections/testingandquality/avoid-global-test-fixture.md @@ -0,0 +1,42 @@ +# Avoid global test fixtures and seeds, add data per-test + +

+ +### One Paragraph Explainer + + Going by the golden testing rule - keep test cases dead-simple, each test should add and act on its own set of DB rows to prevent coupling and easily reason about the test flow. In reality, this is often violated by testers who seed the DB with data before running the tests (also known as ‘test fixture’) for the sake of performance improvement. While performance is indeed a valid concern — it can be mitigated (e.g. In-memory DB, see “Component testing” bullet), however, test complexity is a much painful sorrow that should govern other considerations. Practically, make each test case explicitly add the DB records it needs and act only on those records. If performance becomes a critical concern — a balanced compromise might come in the form of seeding the only suite of tests that are not mutating data (e.g. queries) + +

+ +### Code example: each test acts on its own set of data +```javascript +it("When updating site name, get successful confirmation", async () => { + //test is adding a fresh new records and acting on the records only + const siteUnderTest = await SiteService.addSite({ + name: "siteForUpdateTest" + }); + const updateNameResult = await SiteService.changeName(siteUnderTest, "newName"); + expect(updateNameResult).to.be(true); +}); +``` + +

+ +### Code Example – Anti Pattern: tests are not independent and assume the existence of some pre-configured data +```javascript +before(() => { + //adding sites and admins data to our DB. Where is the data? outside. At some external json or migration framework + await DB.AddSeedDataFromJson('seed.json'); +}); +it("When updating site name, get successful confirmation", async () => { + //I know that site name "portal" exists - I saw it in the seed files + const siteToUpdate = await SiteService.getSiteByName("Portal"); + const updateNameResult = await SiteService.changeName(siteToUpdate, "newName"); + expect(updateNameResult).to.be(true); +}); +it("When querying by site name, get the right site", async () => { + //I know that site name "portal" exists - I saw it in the seed files + const siteToCheck = await SiteService.getSiteByName("Portal"); + expect(siteToCheck.name).to.be.equal("Portal"); //Failure! The previous test change the name :[ +}); +``` \ No newline at end of file From c2eb5cc7407e40ad129806c75a9faa1ef7232576 Mon Sep 17 00:00:00 2001 From: i0natan Date: Sun, 7 Apr 2019 13:00:00 +0300 Subject: [PATCH 2/3] Bullet 4.4 - add data per test --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f70ed660..a76f12c5 100644 --- a/README.md +++ b/README.md @@ -444,7 +444,7 @@ All statements above will return false if used with `===` **TL;DR:** To prevent tests coupling and easily reason about the test flow, each test should add and act on its own set of DB rows. Whenever a test need to pull or assume the existence of some DB data - it must explicitly add that data and avoid mutating any other records -**Otherwise:** Consider a scenario where deployment is aborted due to failing tests, team is now going to spend precious investigation time , do we have a bug? oh no —, it seems that two tests were mutating the same seed data +**Otherwise:** Consider a scenario where deployment is aborted due to failing tests, team is now going to spend precious investigation time that ends in a sad conclusion: the system works well, the tests however interfere with each other and break the build 🔗 [**Read More: Avoid global test fixtures**](/sections/testingandquality/avoid-global-test-fixture.md) From deec76d16b7aa0d8c75601420fe43a7c15a8dd5d Mon Sep 17 00:00:00 2001 From: Yoni Goldberg Date: Wed, 1 May 2019 07:09:17 -0400 Subject: [PATCH 3/3] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a76f12c5..cbdcd205 100644 --- a/README.md +++ b/README.md @@ -442,7 +442,7 @@ All statements above will return false if used with `===` ## ![✔] 4.4 Avoid global test fixtures and seeds, add data per-test -**TL;DR:** To prevent tests coupling and easily reason about the test flow, each test should add and act on its own set of DB rows. Whenever a test need to pull or assume the existence of some DB data - it must explicitly add that data and avoid mutating any other records +**TL;DR:** To prevent tests coupling and easily reason about the test flow, each test should add and act on its own set of DB rows. Whenever a test needs to pull or assume the existence of some DB data - it must explicitly add that data and avoid mutating any other records **Otherwise:** Consider a scenario where deployment is aborted due to failing tests, team is now going to spend precious investigation time that ends in a sad conclusion: the system works well, the tests however interfere with each other and break the build