UUID generator for dependency injection, clean code and testing
When you create objects with auto-generated IDs then it's cumbersome to test them for equality
because the generated attribute value is (duh!) auto-generated.
This library enables you to inject the UUID generator via the strategy pattern and
choose the appropriate implementation for testing as opposed to production.
As for the production-ready implmentation, you can either use UuidGeneratorUuidv4Impl (which uses the "uuid" npm package)
or use any other tool via UuidGeneratorDelegatingImpl.
Brought to you by binary stars GmbH, written in TypeScript and tested with 100% coverage.
- npm i --save @binary-stars/bs-uuid-generator
``TypeScript
// this type is just a tweak, you can use whatever
type Entity
id: string
}
type User = {
name: string
}
// In this example I'm injecting the uuidGenerator into the Data Access Object.
// I think this is a nice design choice but you can have the uuid generated whereever you want instead.
class MyUserDaoWithAutoId {
constructor(private uuidGenerator: UuidGenerator) {}
put(user: User): Entity
return {
...user,
id: this.uuidGenerator.create(),
}
}
}
`
`TypeScript
import UuidGeneratorUuidv4Impl from '@binary-stars/bs-uuid-generator/dist/UuidGeneratorUuidv4Impl'
const dao = new MyUserDaoWithAutoId(new UuidGeneratorUuidv4Impl())
/ ALTERNATIVELY, use any other way to create a UUID Generator /
import UuidGeneratorDelegatingImpl from '@binary-stars/bs-uuid-generator/dist/UuidGeneratorDelegatingImpl'
const genSimpleRandom = () => {
let out = ''
for (let i = 0; i < 32; i++) {
const rand = Math.floor(Math.random() * 16)
if (rand < 10) {
out += ${rand}
} else {
out += String.fromCharCode(rand + 87)
}
}
return out
}
const dao = new MyUserDaoWithAutoId(
new UuidGeneratorDelegatingImpl(genSimpleRandom),
)
`
`TypeScript
import UuidGenerator, {
isUuid,
UuidGeneratorDelegatingImpl,
} from '@binary-stars/bs-uuid-generator/dist/UuidGenerator'
import {
UuidGeneratorFixedImpl,
UuidGeneratorSequenceImpl,
} from '@binary-stars/bs-uuid-generator/dist/UuidGenerators'
let dao: MyUserDaoWithAutoId
describe('Demo', () => {
test("Production Mode: in production we want to use a ROBUST implementation, so let's use the uuid4 lib", () => {
// given
dao = new MyUserDaoWithAutoId(new UuidGeneratorUuidv4Impl())
// when
const actual = dao.put({name: 'Joey'})
// then
expect(actual.name).toEqual('Joey')
expect(actual.id).toBeTruthy()
expect(isUuid(actual.id)).toBe(true)
})
test('... but we could use any other implementation just as well', () => {
// given
const genSimpleRandom = () => {
let out = ''
for (let i = 0; i < 32; i++) {
const rand = Math.floor(Math.random() * 16)
if (rand < 10) {
out += ${rand}
} else {
out += String.fromCharCode(rand + 87)
}
}
return out
}
dao = new MyUserDaoWithAutoId(
new UuidGeneratorDelegatingImpl(genSimpleRandom),
)
// when
const actual = dao.put({name: 'Joey'})
// then
expect(actual.name).toEqual('Joey')
expect(actual.id).toBeTruthy()
expect(isUuid(actual.id)).toBe(true)
})
test('Testing Mode: in testing we want to use a test friendly implementation, e.g. one that always yields the same value', () => {
// given
dao = new MyUserDaoWithAutoId(UuidGeneratorFixedImpl.ONE)
// when
let actual = dao.put({name: 'Joey'})
// then
expect(actual).toEqual({
name: 'Joey',
id: '00000000-0000-0000-0000-000000000001',
})
// the same fact as above:
expect(actual.id).toEqual(UuidGeneratorFixedImpl.ONE.create())
// when 2
actual = dao.put({name: 'CJ'})
// then 2
expect(actual).toEqual({
name: 'CJ',
id: '00000000-0000-0000-0000-000000000001',
})
// the same fact as above:
expect(actual.id).toEqual(UuidGeneratorFixedImpl.ONE.create())
})
test('Testing Mode: ... or an implementation that works like a sequence', () => {
// given
const uuidGenerator = new UuidGeneratorSequenceImpl()
dao = new MyUserDaoWithAutoId(uuidGenerator)
// when
let actual = dao.put({name: 'Joey'})
// then
expect(actual).toEqual({
name: 'Joey',
id: UuidGeneratorSequenceImpl.get(1),
})
// the same fact as above:
expect(actual.id).toEqual('00000000-0000-0000-0000-000000000001')
// when 2
actual = dao.put({name: 'CJ'})
// then 2
expect(actual).toEqual({
name: 'CJ',
id: UuidGeneratorSequenceImpl.get(2),
})
// the same fact as above:
expect(actual.id).toEqual('00000000-0000-0000-0000-000000000002')
})
})
`
- 100% code coverage
- run npm run review` to check style, eslint, run tests and check coverage
- binary stars GmbH, Hausinger Str. 8, 40764 Langenfeld, Germany
- #clean-code #clean-architecture #tdd #xp #agile
- We offer a CTO2Go for your software projects & products + developers, QA engineers and agile project managers
- Wanna know how we achieve 100% coverage EVERY TIME? Contact us about our training & consulting services.
- Our open source projects: https://www.binary-stars.eu/en/open-source-projects/