Skip to content

Instantly share code, notes, and snippets.

View goldbergyoni's full-sized avatar
💭
I may be slow to respond

Yoni Goldberg goldbergyoni

💭
I may be slow to respond
View GitHub Profile
@goldbergyoni
goldbergyoni / nonrealisticdata.js
Last active December 26, 2018 18:46
Anti-Pattern Example: A test suite that passes due to non-realistic data
const addProduct = (name, price) =>{
const productNameRegexNoSpace = /^\S*$/;//no white-space allowd
if(!productNameRegexNoSpace.test(name))
return false;//this path never reached due to dull input
//some logic here
return true;
};
@goldbergyoni
goldbergyoni / realistic.js
Last active December 26, 2018 18:45
Realistic input
it("Better: When adding new valid product, get successful confirmation", async () => {
const addProductResult = addProduct(faker.commerce.productName(), faker.random.number());
//Generated random input: {'Sleek Cotton Computer', 85481}
expect(addProductResult).to.be.true;
//Test failed, the random input triggered some path we never planned for.
//We discovered a bug early!
});
@goldbergyoni
goldbergyoni / pbt.js
Created December 26, 2018 14:14
property based testing
require('mocha-testcheck').install();
const {expect} = require('chai');
const faker = require('faker');
describe('Product service', () => {
describe('Adding new', () => {
//this will run 100 times with different random properties
check.it('Add new product with random yet valid properties, always successful',
gen.int, gen.string, (id, name) => {
expect(addNewProduct(id, name).status).to.equal('approved');
@goldbergyoni
goldbergyoni / using-hooks.js
Last active December 26, 2018 14:18
Tests are not independent and rely on some global hook to feed global DB data
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);
});
@goldbergyoni
goldbergyoni / independenttest.js
Created December 26, 2018 14:20
Doing It Right Example: We can stay within the test, each test acts on its own set of data
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);
});
@goldbergyoni
goldbergyoni / catch-in-test.js
Last active December 30, 2018 07:25
Anti-pattern Example: A long test case that tries to assert the existence of error with try-catch
it("When no product name, it throws error 400", async() => {
let errorWeExceptFor = null;
try {
const result = await addNewProduct({name:'nest'});}
catch (error) {
expect(error.code).to.equal('InvalidInput');
errorWeExceptFor = error;
}
expect(errorWeExceptFor).not.to.be.null;
//if this assertion fails, the tests results/reports will only show
@goldbergyoni
goldbergyoni / right-test-with-error.js
Created December 26, 2018 14:23
Doing It Right Example: A human-readable expectation that could be understood easily, maybe even by QA or technical PM
it.only("When no product name, it throws error 400", async() => {
expect(addNewProduct)).to.eventually.throw(AppError).with.property('code', "InvalidInput");
});
@goldbergyoni
goldbergyoni / tag-test.js
Last active January 1, 2019 10:10
Doing It Right Example: Tagging a test so we can later run only a selection of tests that suits our scenario
//this test is fast (no DB) and we're tagging it correspondigly
//now the user/CI can run it frequently
describe('Order service', function() {
describe('Add new order #cold-test #sanity', function() {
it('Scenario - no currency was supplied. Excpectation - Use the default currency #sanity', function() {
//code logic here
});
});
});
@goldbergyoni
goldbergyoni / component-test.js
Last active December 26, 2018 14:28
Doing It Right Example: Supertest allows approaching Express API in-process (fast and cover many layers)
//can choose here whether to test in-process or against external URL
const app = express();
app.get('/user', function(req, res) {
res.status(200).json({ name: 'john' });
});
request(app)
.get('/user')
.expect('Content-Type', /json/)
@goldbergyoni
goldbergyoni / middleware-test.js
Created December 26, 2018 14:29
Doing It Right Example: Testing middleware in isolation without issuing network calls and waking-up the entire Express machine
//the middleware we want to test
const unitUnderTest = require('./middleware')
const httpMocks = require('node-mocks-http');
//Jest syntax, equivelant to describe() & it() in Mocha
test('A request without authentication header, should return http status 403', () => {
const request = httpMocks.createRequest({
method: 'GET',
url: '/user/42',
headers: {
authentication: ''