๐ŸŒณ๋ชฉํ‘œ

์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“ค์—ˆ๋˜ server.js๋Š” http ๋ชจ๋“ˆ์„ ์ง์ ‘ ๊ฐ€์ ธ๋‹ค ์‚ฌ์šฉํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ชจ๋“ˆ์˜ createServer() ํ•จ์ˆ˜์™€ listen() ํ•จ์ˆ˜๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ–ˆ์ฃ .

์™ธ๋ถ€ ๋ชจ๋“ˆ ํ˜น์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋”ฐ์œ„๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ํ•œ ๋ฒˆ ๋ž˜ํ•‘ํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ ์ฝ”๋“œ๊ฐ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ๊ฐ•ํ•˜๊ฒŒ ์ปคํ”Œ๋ง ๋˜์ง€ ์•Š๋„๋ก ํ•˜๋Š”๊ฒƒ์ด์ฃ . ํ•œ ๋‹จ๊ณ„ ๋ฒ„ํผ๋ฅผ ๋‘ฌ์„œ ์™ธ๋ถ€ ์ฝ”๋“œ์˜ ๋ณ€ํ™”์— ์œ ์—ฐํ•˜๊ฒŒ ๋Œ€์ฒ˜ํ•˜๊ธฐ ์œ„ํ•ฉ๋‹ˆ๋‹ค.

Application ๋ชจ๋“ˆ

๊ทธ๋ž˜์„œ โ€œApplicationโ€ ์ด๋ž€ ์ด๋ฆ„์œผ๋กœ ๋ชจ๋“ˆ์„ ๋‹ค์‹œ ๋งŒ๋“ค์–ด ๋ณผ๊ฑฐ์—์š”. ์ด ๋ชจ๋“ˆ์€ http๋ฅผ ๋‚ด๋ถ€์ ์œผ๋กœ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๊ณ ์š”.

๋จผ์ € ์ง€๋‚œ ์‹œ๊ฐ„๊นŒ์ง€ ํ–ˆ๋˜ ์ฝ”๋“œ๋กœ ์ด๋™ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

$ git checkout -f application/listen-spec

์ถ”๊ฐ€ ๋ชจ๋“ˆ(sinon)์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— package.json์— ๊ธฐ๋กํ•œ ๋ชจ๋“ˆ์„ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.

$ npm install

src ํด๋”์— Application.spec.js ํŒŒ์ผ๋ถ€ํ„ฐ ์‚ดํŽด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“ค Application ๋ชจ๋“ˆ์˜ ์š”๊ตฌ์‚ฌํ•ญ์„ ํ…Œ์Šคํฌ ์ฝ”๋“œ๋กœ ์ž‘์„ฑํ•ด ๋‘” ๊ฒƒ์ด์ฃ .

๋„ค ๋ถ€๋ถ„์œผ๋กœ ๋‚˜๋ˆ ์„œ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

describe('Application', () => { 
  describe('listen()', () => { 
    it('server ๊ฐ์ฒด์˜ listen ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•œ๋‹ค', () => { 

์ด์ „ ๊ธ€์—์„œ ๋ชจ์นด๋ฅผ ์†Œ๊ฐœํ–ˆ์—ˆ์ฃ ? ๋ชจ์นด๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด์ฃผ๋Š” ํ…Œ์ŠคํŠธ ๋Ÿฌ๋„ˆ์ž…๋‹ˆ๋‹ค. ๋ชจ์นด ํ”„๋ ˆ์ž„์›์ด ์ œ๊ณตํ•˜๋Š” API ํ•จ์ˆ˜๊ฐ€ ๋ช‡ ๊ฐœ์žˆ๋Š”๋ฐ์š”, ์ €๋Š” describe()๊ณผ it()์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

  • descirbe(): ํ…Œ์ŠคํŠธ ๊พธ๋Ÿฌ๋ฏธ(Test Suite)๋ผ๊ณ  ํ•˜๋ฉฐ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์„ ๊ธฐ์ˆ ํ•จ
  • it(): ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค(Test Case)๋ผ๊ณ  ํ•˜๋ฉฐ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ •์˜ํ•จ

์œ„ ์ฝ”๋“œ๋Š” โ€œApplication ๋ชจ๋“ˆ์˜ listen() ๋ฉ”์†Œ๋“œ๋ฅผ ํ…Œ์ŠคํŠธโ€ ํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ์ด ๋ฉ”์†Œ๋“œ๋Š” โ€œserver ๊ฐ์ฒด์˜ listen ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•œ๋‹คโ€๋ผ๋Š” ํ…Œ์ŠคํŠธ์ธ ๊ฒƒ์ด์ฃ .

  // arrange
  const app = App(); // const App = require('./Application') ์œผ๋กœ ๊ฐ€์ ธ์™”๋‹ค๊ณ  ๊ฐ€์ •
  const spy = sinon.spy();
  app._server.listen = spy

์œ ๋‹› ํ…Œ์ŠคํŠธ๋Š” ๋ณดํ†ต ์„ธ ๋‹จ๊ณ„๋กœ ๋‚˜๋ˆ•๋‹ˆ๋‹ค.

  • ์ค€๋น„(arragne) -> ์‹คํ–‰(act) -> ๊ฒ€์ฆ(assert)

์œ„ ์ฝ”๋“œ๋Š” ์ฒซ ๋ฒˆ์งธ ์ค€๋น„ ๋‹จ๊ณ„๋ฅผ ์ •์˜ํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐ์ฒด์™€ ์ŠคํŒŒ์ด๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  app._server ๊ฐ์ฒด์˜ listen ์†์„ฑ์— ์ŠคํŒŒ์ด๋ฅผ ์‹ฌ์–ด ๋‘์—ˆ์ฃ . ์ŠคํŒŒ์ด๋ฅผ ์‹ฌ์€ ์ด์œ ๋Š” ๊ฒ€์ฆํ• ๋•Œ listen ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜์—ˆ์ง€๋Š” ์ŠคํŒŒ์ด๋กœ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ž…๋‹ˆ๋‹ค.

  // act 
  app.listen()

์‹ค์ œ ํ…Œ์ŠคํŠธ ํ•ด์•ผํ•  ๋ฉ”์†Œ๋“œ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

  // assert
  should(spy.called).be.equal(true);

listen ๋ฉ”์†Œ๋“œ๊ฐ€ ์‹คํ–‰๋˜์—ˆ๋Š”์ง€ ์ŠคํŒŒ์ด๋ฅผ ํ†ตํ•ด ๊ฒ€์‚ฌํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ๋ฅผ ๋Œ๋ ค ๋ณผ๊นŒ์š”?

$ npm t

Error: Cannot find module './Application'

์ด๊ฒƒ๋ณด๋‹ค ๋งŽ์€ ๋ฉ”์„ธ์ง€๊ฐ€ ๋‚˜์˜ค์ง€๋งŒ Application ๋ชจ๋“ˆ์„ ์ฐพ์ง€ ๋ชปํ•˜๋Š”๊ฒŒ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค. ์™œ๋ƒ๋ฉด ์šฐ๋ฆฌ๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋งŒ ๋งŒ๋“ค์—ˆ์ง€ ๋Œ€์ƒ์ด ๋˜๋Š” Application.js ๋Š” ๋งŒ๋“ค์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์ด์ฃ .

๐Ÿค์‹ค์Šต - Application ๋ชจ๋“ˆ๊ณผ listen ๋ฉ”์†Œ๋“œ ๊ตฌํ˜„

Application ๋ชจ๋“ˆ์„ ๊ตฌํ˜„ํ•ด ๋ณด์„ธ์š”. Application์€ listen ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ตฌํ˜„ํ•œ ๋’ค์—๋Š” ๋ฐ˜๋“œ์‹œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ํ†ต๊ณผํ•ด์•ผ ํ•˜๊ตฌ์š”.

๐Ÿคํ’€์ด

์ž ๊ทธ๋Ÿผ ๊ฐ™์ด ํ’€์–ด ๋ณผ๊นŒ์š”? ์„ธ ๋‹จ๊ณ„๋กœ ๋‚˜๋ˆ  ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

const http = require('http')

const Application = () => {
  const listen = () => {

  }
  
  return {
    listen
  }
}

module.exports = Application

๋จผ์ € http ๋ชจ๋“ˆ์„ ๊ฐ€์ ธ์™”์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๋ชจ๋“ˆ ํŒจํ„ด์œผ๋กœ Application์„ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“ˆ ํŒจํ„ด์€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”๋ฐ์š”, ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์— ์žˆ๋Š” listen ํ•จ์ˆ˜๋ฅผ ๋„ฃ์–ด์„œ ๋ฐ˜ํ™˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ์•„์ง ์ด๊ฑด ๋นˆ ํ•จ์ˆ˜์ด๊ณ ์š”. ๋งˆ์ง€๋ง‰ ์ค„์— Application์„ ๋ชจ๋“ˆ๋กœ ๋งŒ๋“ค์–ด์„œ ์™ธ๋ถ€์—์„œ ์‚ฌ์šฉํ•˜๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.

 const _server = http.createServer((req, res) => {
    res.statusCode = 200
    res.setHeader('Content-Type', 'text/plain')
    res.end('Hello World\n')
  });

  // ...

  return {
    _server,
    listen
  }

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์— ๋ณด๋ฉด _server ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ์ŠคํŒŒ์ด๋ฅผ ์‹ฌ์–ด๋‘๊ณ  ์žˆ์ฃ . ์ด๊ฑด ํ…Œ์ŠคํŠธ ์šฉ๋„๋กœ ๋…ธ์ถœํ•˜๋Š” ๊ฒƒ์ด๋ผ ๋ณ€์ˆ˜ ์ด๋ฆ„ ์•ž์— ์–ธ๋”์Šค์ฝ”์–ด(_)๋ฅผ ๋ถ™์˜€์Šต๋‹ˆ๋‹ค. http.createServer() ํ•จ์ˆ˜๋กœ ์„œ๋ฒ„๋ฅผ ๋งŒ๋“ค์–ด _server์— ์ €์žฅํ–ˆ๊ณ  ์™ธ๋ถ€๋กœ ๋…ธ์ถœํ•˜์˜€์Šต๋‹ˆ๋‹ค.

  const listen = (port = 3000, hostname = '127.0.0.1', fn) => {
    _server.listen(port, hostname, fn)
  }

์ƒ์„ฑํ•œ _server ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด listen ํ•จ์ˆ˜ ์ฝ”๋“œ๋ฅผ ์ฑ„์›Œ ๋„ฃ์—ˆ์Šต๋‹ˆ๋‹ค. ํฌํŠธ ๋ฒˆํ˜ธ์™€ ํ˜ธ์ŠคํŠธ๋ช… ๊ธฐ๋ณธ ์ธ์ž๊ฐ’์„ ์„ค์ •ํ•ด์„œ ๋ฐฉ์–ด ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค์—ˆ๊ตฌ์š”. ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์—์„œ listen ํ•จ์ˆ˜ ํ˜ธ์ถœ์—ฌ๋ถ€๋ฅผ ์ฒดํฌํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— _server.listen()์„ ํ˜ธ์ถœํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•ด ๋ณผ๊นŒ์š”?

$ npm test

  Application
    listen()
      โœ“ server ๊ฐ์ฒด์˜ listen ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•œ๋‹ค

  1 passing (8ms)

์„ฑ๊ณต์ ์œผ๋กœ ํ†ต๊ณผํ–ˆ๋„ค์š”.

server.js๋ฅผ app.js๋กœ ์ด๋ฆ„์„ ๋ฐ”๊พธ๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด์ œ๋Š” ์„œ๋ฒ„๋ผ๊ธฐ๋ณด๋‹ค๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ชจ๋“ˆ์„ ์ด์šฉํ•œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐ์ฒด๋ผ๋Š” ์˜๋ฏธ์ฃ . app.js ์ฝ”๋“œ๋ฅผ ๋ณผ๊นŒ์š”?

const App = require('./src/Application');
const app = App();

module.exports = app;

Application ๋ชจ๋“ˆ์„ ๊ฐ€์ ธ์™€ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด app์— ์ €์žฅํ–ˆ์ฃ . ๊ณง์žฅ ๋ชจ๋“ˆ๋กœ ๋…ธ์ถœํ–ˆ์Šต๋‹ˆ๋‹ค.

bin.js๋„ ๋ณผ๊นŒ์š”?

const app  = require('./app');
const hostname = '127.0.0.1';
const port = 3000;

app.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

โ€œserverโ€ ๋Œ€์‹  โ€œappโ€ ๋ชจ๋“ˆ์„ ๊ฐ€์ ธ์˜จ ๊ฒƒ๋งŒ ๋‹ฌ๋ผ์กŒ์Šต๋‹ˆ๋‹ค.

์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์ž˜ ๋™์ž‘ํ•˜๋„ค์š”.

npm start

Server running at http://127.0.0.1:3000/

Application ๋ชจ๋“ˆ์€ ์•„๋ž˜ ์ดˆ๋ก์ƒ‰ ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค. ๋“œ๋””์–ด ์ต์Šคํ”„๋ ˆ์ŠคJS์˜ ์ฒซ๋ฒˆ์งธ ๋ชจ๋“ˆ์„ ๋งŒ๋“ค์—ˆ๊ตฐ์š”.

์ •๋ฆฌ

  • http๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  Application ๊ฐ์ฒด๋กœ ์ถ”์ƒํ™” ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๋ชฉ์ฐจ ๋ฐ”๋กœ๊ฐ€๊ธฐ