TDD

Модульный тест (Unit test)

Модульный тест применяется для тестирования одной логически выделенной и изолированной единицы системы. Чаще всего это метод класса или простая функция (хотя я допускаю и весь класс). Изолированность тестируемой единицы достигается при помощи Заглушек (Stubs, Dummies) и Макетов (Mockups).

Системный тест (System test)

Это комплексный тест, который тестирует связку сразу нескольких компонентов. Можно сказать, что это модульный тест, где модуль — это связка компонентов. Связка объединена неким фасадом, который предоставляет соответствующий API к ней. Методы этого API — это как раз то, что нам и надо покрыть тестами. Изолированность связки достигается по средствам Заглушек (Stubs, Dummies) и Макетов (Mockups). Факт связанности компонентов и формат коммуникации между ними проверяется с помощью так называемых Шпионов (Spies).🤠
  1. Используют сеть, БД, ФС

Инструменты 🛠

  1. Assert - утверждение
  1. Assert - утверждение
  2. Spy - отслеживает вызовы
  3. Stub - возвращает что-либо
  4. Mock - все и сразу 🔥
  5. Подмена модулей в runtime 🔥💣💥

Тестируемый код

  1. Конструктор не должен делать какую-либо работу

Express.js 🧐

Обычный роутер

			const express = require("express");
			dbHelper = require("dbHelper"); //💩
			 
			const router = express.router();
			 
			router.get("/:id", (req, res, next) => {
				return dbHelper.anyTable.getById(req.params.id)
				  .then(obj => res.json(obj))
				  .catch(() => {...});
			});
			 
			module.exports = router;	
		

Тестируемый роутер

			const express = require("express");
			module.exports = (app, dbHelper👍) => {
				const router = express.Router();
			 
				app.use("/", router);
			 
				router.get("/:id", (req, res, next) => {
				  return dbHelper.anyTable.getById(req.params.id)
					.then(obj => res.json(obj))
					.catch(() => {...});
				});
			};
		

Unit test для роутера

			const request = require("supertest");
			const app = require("express")();
			const dbHelperMock = {...mocks};
			require("routes/index")(app, dbHelperMock);
			describe("app", () => {
				it("works", done => {
				  request(app).get("/1")
					.expect(200, done);
				});
			 
				it("fails", done => {
				  request(app).get("/2")
					.expect(404, done);
				});
			});
		

📖

  1. Разработка через тестирование. Кент Бек
  2. Тесты, которые должен писать разработчик
  3. Best Practices for Spies, Stubs and Mocks in Sinon.js
  4. Unit Testing Express Routers
  5. Mockанье зависимостей в node.js приложениях
  6. How to Think About the "new" Operator with Respect to Unit Testing

🎞️

  1. Dependency Rejection and TDD without Mocks
  2. Как всё починить и ничего не сломать: работа со сложным кодом при помощи тестов