<p>sinon.restore () &amp;&amp; sandbox.restore () ๊ฐ€์งœ๋ฅผ ๋ณต์›ํ•˜์ง€ ์•Š์Œ</p>

์— ๋งŒ๋“  2019๋…„ 07์›” 23์ผ  ยท  16์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: sinonjs/sinon

๋ฒ„๊ทธ ์„ค๋ช…
๊ฐ€์งœ sinon.restore() ( resetHistory , resetBehavior ๋˜๋Š” reset )๋ฅผ ์ง€์šธ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ƒˆ ์ƒŒ๋“œ ๋ฐ•์Šค๋ฅผ ๋งŒ๋“ค๊ณ  ์ƒŒ๋“œ ๋ฐ•์Šค๋ฅผ ์ง€์šฐ๋ ค๊ณ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ฃผ์‚ฌ์œ„๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์˜๋„์ ์ž…๋‹ˆ๊นŒ?

์žฌํ˜„ํ•˜๋ ค๋ฉด

it("Demonstrates how to restore a fake", () => {
  let sandbox = sinon.createSandbox();
  let thing = sandbox.fake();
  thing("Hi");
  expect(thing.calledOnce).to.be.true;
  expect(thing.lastArg).to.equal("Hi");
  sandbox.restore();
  sandbox.resetHistory();
  sandbox.resetBehavior();
  sandbox.reset();
  expect(thing.calledOnce).to.be.false; // Fails. thing.calledOnce === true
  expect(thing.lastArg).to.be.undefined; // Fails if above commented out. thing.lastArg === "Hi"
});

์˜ˆ์ƒ๋˜๋Š” ํ–‰๋™
thing.lastArg ๋Š” undefined ๋˜๋Š” null ๋  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋‚˜์—๊ฒŒ "Hi"

์Šคํฌ๋ฆฐ ์ƒท
ํ•ด๋‹น ์‚ฌํ•ญ ์—†์Œ

์ปจํ…์ŠคํŠธ (๋‹ค์Œ ์ •๋ณด๋ฅผ ์ž‘์„ฑํ•˜์‹ญ์‹œ์˜ค) :

  • ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฒ„์ „ : Sinon ^ 7.3.2
  • ํ™˜๊ฒฝ : ๋…ธ๋“œ 10.16.0
  • ์˜ˆ์ œ URL : N / a
  • ์‚ฌ์šฉ์ค‘์ธ ๊ธฐํƒ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ : Mocha, Chai

์ถ”๊ฐ€ ์ปจํ…์ŠคํŠธ
๋ฐฑ์—”๋“œ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” Sinon์˜ ๊ธฐ๋Šฅ์„ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ๋งŒํ•˜๋ฉด๋ฉ๋‹ˆ๋‹ค.

Bug Help wanted

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

์ถฉ๋ถ„ํžˆ ๊ณตํ‰ํ•ฉ๋‹ˆ๋‹ค-์„ค๋ช… ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

2021 ๋…„ 2 ์›” 19 ์ผ ๊ธˆ์š”์ผ ์˜ค์ „ 7:02 Carl-Erik Kopseng [email protected]
์ผ๋‹ค :

@scottpatrickwright https://github.com/scottpatrickwright ํ์‡„๋˜์—ˆ์Šต๋‹ˆ๋‹ค
์Šค๋ ˆ๋“œ์—์„œ ๋ช…๋ฐฑํ•œ ๋ฒ„๊ทธ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ƒฅ
๊ท€ํ•˜์˜ ๊ฒฝ์šฐ์™€ ๊ฐ™์ด ์‚ฌ์šฉ์ž ์˜ค๋ฅ˜ : ์„ค๋ช… ๋ฐ ์˜๋„๋Œ€๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค :-)

Sinon ์ƒŒ๋“œ ๋ฐ•์Šค๋Š” ์•Œ๊ณ ์žˆ๋Š” ์ •๋ณด๋ฅผ ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” Sinon์ด
์ƒํ˜ธ ์ž‘์šฉํ•˜๋Š” ๋Œ€์ƒ์— ๋Œ€ํ•œ ์ง€์‹์„ ๊ฐ–์Šต๋‹ˆ๋‹ค. ์Šคํ… ๋‹น์‹ 
์œ„์˜ ์„ค๋ช…์€ ๋…๋ฆฝํ˜•์œผ๋กœ ๋งŒ๋“ค์–ด์ง‘๋‹ˆ๋‹ค. Sinon์€
ํ• ๋‹น ํ•œ ๊ฐœ์ฒด. ๋‘ ๋ฒˆ์งธ ์˜ˆ์—์„œ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค. ๋‹น์‹ ์€ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
๋˜ํ•œ sinon.replace (obj, fieldname, fake)๋ฅผ ์ˆ˜ํ–‰ํ•˜์—ฌ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค. ๊ทธ๋ƒฅ
์ž๋ฐ” ์Šคํฌ๋ฆฝํŠธ ๐Ÿ™‚

โ€”
๋‹น์‹ ์ด ์–ธ๊ธ‰ ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ๋ฐ›๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
์ด ์ด๋ฉ”์ผ์— ์ง์ ‘ ๋‹ต์žฅํ•˜๊ณ  GitHub์—์„œ ํ™•์ธํ•˜์„ธ์š”.
https://github.com/sinonjs/sinon/issues/2065#issuecomment-782032440 ๋˜๋Š”
๊ตฌ๋… ์ทจ์†Œ
https://github.com/notifications/unsubscribe-auth/AAKKRTFVMGEYVIB5GSIDXKTS7ZHMRANCNFSM4IGBASQQ
.

๋ชจ๋“  16 ๋Œ“๊ธ€

ํ˜„์žฌ๋กœ์„œ๋Š” _ ๋ฒ„๊ทธ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ _ ์†”์งํžˆ ์ €๋Š” ์ด๊ฒƒ์— ๋Œ€ํ•ด ์™„์ „ํžˆ ํ™•์‹ ํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€์งœ์— ๋Œ€ํ•œ ์š”์ ์€ ์–ด๋–ค ์˜๋ฏธ์—์„œ๋Š” ๋ถˆ๋ณ€์ด์–ด์•ผํ•œ๋‹ค๋Š” ์ ์„ ๊ธฐ์–ตํ•˜์ง€๋งŒ, ์ƒํƒœ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— (์ฆ‰, ํ˜ธ์ถœ๋˜์—ˆ๋Š”์ง€ ์•Œ๊ณ  ์žˆ์Œ) ๋ถˆ๋ณ€์„ฑ์€ ์Šคํ„ฐ ๋น™ ๋™์ž‘์œผ๋กœ ๋งŒ ์ œํ•œ๋˜์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

@mroderick ์ด ๋Œ€๋‹ตํ•˜๊ธฐ์— ์ ํ•ฉํ•œ ์‚ฌ๋žŒ์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ...

์ด๊ฒƒ์ด ์˜ฌ๋ฐ”๋ฅธ ๋™์ž‘์ด๋ผ๋ฉด ์ตœ์†Œํ•œ ๋ฌธ์„œ๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

@ fatso83 ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! .restore ๋ฌธ์„œ๋Š” ๊ฐ€์งœ๋ฅผ ์–ธ๊ธ‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

image

์—ฌ๊ธฐ์—์„œ .

์ด ๋ฒ„๊ทธ๋Š” ๋‚˜ ์ž์‹ ์ด ์กฐ๊ธˆ๋งŒ ์žˆ์—ˆ์œผ๋ฏ€๋กœ ์ˆ˜์ •ํ•˜๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฉฐ์น  ๋™์•ˆ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด PR์„ํ•˜์ง€ ์•Š์œผ๋ฉด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์‹œ๊ฐ„์„ ์ฐพ์„ ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์„ ์ง€๊ธˆ ์กฐ์‚ฌํ–ˆ๊ณ  ์œ„์˜ ํ…Œ์ŠคํŠธ์™€ ๊ฐ™์ด ๋ฌธ์„œ๋Š” ์•ฝ๊ฐ„ ์˜คํ•ด์˜ ์†Œ์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ๋Š” (๊ฑฐ์˜) ๋งํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ๋จผ์ € ๋ช‡ ๊ฐ€์ง€ ์šฉ์–ด๋ฅผ ์ •์˜ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ณต์› -์ƒŒ๋“œ ๋ฐ•์Šค๋ฅผ ๋ณต์›ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ๋ชจ๋“  ์Šคํ… ๊ธฐ๋Šฅ์„ ์›๋ž˜ ์ƒํƒœ๋กœ ๋ณต์›ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ์Šคํ…์ด ์›๋ณธ์„ ๋ฎ์–ด ์“ฐ๋ฉด ๊ฐ ๊ฐœ์ฒด์—์„œ ์ œ๊ฑฐ๋ฉ๋‹ˆ๋‹ค.
์žฌ์„ค์ • -์žฌ์„ค์ •์€ ์ƒ์„ฑ ๋œ ๊ฐ ํŽ˜์ดํฌ์˜ ์ƒํƒœ๊ฐ€ ์ง€์›Œ์ง€์ง€ ๋งŒ ๊ฐœ์ฒด์—๋Š” ์—ฌ์ „ํžˆ ์กด์žฌ ํ•จ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์œ„ ํ…Œ์ŠคํŠธ์˜ ๋ฌธ์ œ์ ์€

  1. ์ƒŒ๋“œ ๋ฐ•์Šค์—์„œ ๋ชจ๋“  ๊ฐ€์งœ๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
  2. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ƒŒ๋“œ ๋ฐ•์Šค (ํ˜„์žฌ ๋น„์–ด ์žˆ์Œ)์—์„œ ๊ฐ€์งœ ์ปฌ๋ ‰์…˜์„ ์ง„ํ–‰ํ•˜๊ณ  ๊ฐ€์งœ ๋ชฉ๋ก (๋นˆ)์„ ์žฌ์„ค์ •ํ•˜๋ ค๊ณ ํ•ฉ๋‹ˆ๋‹ค.

๋ง์ด ์•ˆ๋ผ :-)

๋‚˜๋Š” ํ…Œ์ŠคํŠธํ–ˆ๊ณ  reset ๋ฐ restore ํ˜ธ์ถœ์ด ์ œ๋Œ€๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๊ฑฐ์˜ ... reset ๋Š” calledOnce ์˜ ์ƒํƒœ๋ฅผ ์ •๋ฆฌํ•˜์ง€๋งŒ lastArgument ์€ (๋Š”) ์ •๋ฆฌ๋˜์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์„ธ๋ถ€ ์‚ฌํ•ญ์„ ์žƒ์–ด ๋ฒ„๋ ธ๋Š”์ง€ ์ข€ ๋” ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

์žฌํ˜„ ํ•  ์ˆ˜์—†๋Š” ๊ฒƒ์œผ๋กœ ์ข…๋ฃŒํ•˜์ง€๋งŒ fake.lastArg ๋ฒ„๊ทธ์— ๋Œ€ํ•œ ์ƒˆ๋กœ์šด ๋ฌธ์ œ๊ฐ€ ์—ด๋ฆฝ๋‹ˆ๋‹ค.

ํ™•์ธํ•˜๋ ค๋ฉด : https://runkit.com/fatso83/sinon-issue-2065

์ด ๋ฒ„๊ทธ๊ฐ€ ๋‚˜์—๊ฒŒ๋„ ๋ฐœ์ƒํ•˜๊ณ  ์žˆ์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ตฌํ˜„์ด ๊ทธ๋Œ€๋กœ ์œ ์ง€๋˜์–ด์•ผํ•˜๋Š” ํ…Œ์ŠคํŠธ ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์žˆ์ง€๋งŒ ํ•จ์ˆ˜๋Š” ์ด์ „ ํ…Œ์ŠคํŠธ์˜ ์Šคํ… ๊ฒฐ๊ณผ๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, sandbox.restore() ์ด (๊ฐ€) ํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

7.5.0 ๋ฒ„์ „์—์„œ ์ด๋Ÿฐ ์ผ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

@ oscarr-reyes https://github.com/sinonjs/sinon/commit/54df7f7000a9db2dd05319daa49518f3cd5a5dd7์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์•„์ง ์ƒˆ ๋ฆด๋ฆฌ์Šค๋กœ ๋งŒ๋“ค์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

@ oscarr-reyes ์žฌํ˜„ ๊ฐ€๋Šฅํ•œ ์˜ˆ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์šฐ๋ฆฌ๋Š” ์•„์ง์ด ๋ฒ„๊ทธ๋ฅผ ๋ณด์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ์œ„์˜ ์Šค๋ ˆ๋“œ์™€ ์ œ ์„ค๋ช…์„ ์‚ดํŽด๋ณด๋ฉด ์šฐ๋ฆฌ๊ฐ€ ๋ฐœ๊ฒฌ ํ•œ ์œ ์ผํ•œ ๋ฒ„๊ทธ๋Š” ํ•˜๋‚˜์˜ ํ”Œ๋ž˜๊ทธ๊ฐ€ ์ง€์›Œ์ง€์ง€ ์•Š์€ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๋ชจ๋“  ๊ฒƒ์ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์‹ค์ œ๋กœ ์ฆ๋ช…์„ ๋ณด์ง€ ์•Š๋Š” ํ•œ ๋ฒ„๊ทธ๋Š” ์—†์Šต๋‹ˆ๋‹ค (lastArg ํ”Œ๋ž˜๊ทธ๋ฅผ ์ œ์™ธํ•˜๊ณ ).

๋‚˜๋Š” ๊ฐ™์€ ๋ฌธ์ œ์— ์ง๋ฉดํ–ˆ๋‹ค.

๋‚ด "validateCaptcha"๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ƒŒ๋“œ ๋ฐ•์‹ฑํ•˜๊ณ  ๋ณต์› ํ•  ๋•Œ ์Šคํ…์„ ๊ณ„์† ๋ฐœํ–‰ํ•ฉ๋‹ˆ๋‹ค.

/src/middlewares/captcha.js

const request = require("got");

const validateCaptcha = async (req, res, next) => {
    // if (process.env.NODE_ENV !== "production") return next();

    const captcha = req.body["g-recaptcha-response"] || req.body.g_recaptcha_response;

    // g-recaptcha-response is the key that browser will generate upon form submit.
    // if its blank or null means user has not selected the captcha, so return the error.
    if (captcha === undefined || captcha === "" || captcha === null)
        return res
            .status(400)
            .json({ message: "Please, verify that you are not a robot" });

    // Put your secret key here.
    const secretKey = process.env.GOOGLE_CAPTCHA_API_SECRET_KEY;

    // req.connection.remoteAddress will provide IP address of connected user.
    const verificationUrl = `https://www.google.com/recaptcha/api/siteverify?secret=${secretKey}&response=${captcha}`;

    try {

        // Hitting GET request to the URL, Google will respond with success or error scenario.
        const { body } = await request.post(verificationUrl, { responseType: "json" });

        // Success will be true or false depending upon captcha validation.
        if (body.success !== undefined && !body.success)
            return res
                .status(400)
                .json({ message: "Captcha validation error" });
    } catch (error) {
        return res
            .status(503)
            .json({ message: "Couldn't validate captcha" });
    }

    next();
};

module.exports = {
    validateCaptcha,
};

/test/api/user.spec.js

require("../setup.spec");
const supertest = require("supertest");
const captcha = require("../../src/middlewares/captcha");
const sinon = require("sinon");
let app;
let agent;
let sandbox;

const login = (anAgent, userCredentials) =>
    anAgent
        .post("/api/users/signIn")
        .send(userCredentials);

const logout = (anAgent) =>
    anAgent
        .post("/api/users/signOut");

describe("User endpoints", function () {
    this.beforeAll(async () => {
        sandbox = sinon.createSandbox();
        sandbox
            .stub(captcha, "validateCaptcha")
            .callsFake(async (req, res, next) => {
                console.log("Validate Captcha FAKE");
                return next();
            });
        // sandbox.restore();
    });

    this.beforeEach(async () => {
        app = require("../../src/app");
        agent = supertest.agent(app);
        const sequelize = require("../../src/models");
        await sequelize.sync({ force: true });

        const Customer = require("../../src/models/customer");
        const User = require("../../src/models/user");
        await Customer.create(
            {
                firstName: "Test",
                lastName: "Customer",
                user: {
                    email: "[email protected]",
                    password: "boo",
                },
            },
            {
                include: [User],
            }
        );
    });

    this.afterEach(async () => {
        sandbox.restore();
    });

    it("should create a new user", function (done) {
        agent
            .post("/api/users/signUp")
            .send({
                firstName: "firstName",
                lastName: "lastName",
                email: "[email protected]",
                password: "aPassword",
            })
            .expect(201)
            .end((err, res) => {
                err ? done(err) : done();
            });
    });

    it("should sign in", function (done) {
        login(agent, { email: "[email protected]", password: "boo" })
            .expect(200)
            .end((err, res) => {
                const { message, user } = res.body;
                message.should.be.equal("valid");
                user.should.have.property("email").equal("[email protected]");
                user.should.have.property("customer").have.property("firstName").equal("Test");
                user.should.have.property("customer").have.property("lastName").equal("Customer");

                agent
                    .get("/api/users/me")
                    .expect(200)
                    .end((err, res) => {
                        const user = res.body;
                        user.should.have.property("email").equal("[email protected]");
                        user.should.have.property("customer").have.property("firstName").equal("Test");
                        user.should.have.property("customer").have.property("lastName").equal("Customer");
                        err ? done(err) : done();
                    });
            });
    });

    it("should sign out", async function () {
        await login(agent, { email: "[email protected]", password: "boo" });
        await logout(agent)
            .expect(302)
            .expect("Location", "/");

        return agent
            .get("/api/users/me")
            .expect(401);
    });

    it("should return unauthorized", function (done) {
        agent
            .get("/api/users/me")
            .expect(401)
            .end((err, res) => {
                err ? done(err) : done();
            });
    });
});

์ž‘๋™ํ•˜์ง€ ์•Š๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ๋‚ด๊ฐ€ํ•˜๋Š” ์ผ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.
1) ์ฒซ ๋ฒˆ์งธ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ๋ชจ์˜
2) ๋‹ค์Œ ํ•ญ๋ชฉ์— ๋Œ€ํ•ด ๋ณต์›ํ•˜์‹ญ์‹œ์˜ค.

beforeAll ์•ˆ์— "sandbox.restore ();"๋ผ๋Š” ์ฃผ์„์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์‹œ๋„ํ–ˆ๊ณ  ๊ฑฐ๊ธฐ์—์„œ ์ž‘๋™ํ–ˆ์Šต๋‹ˆ๋‹ค ...ํ•˜์ง€๋งŒ ์“ธ๋ชจ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค

๋‚˜๋Š” ๋˜ํ•œ ๋‚ด app.js์— ๋งค๋ฒˆ ์š”๊ตฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

5 ๋ถ„ ์ „์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

require("../setup.spec");
const decache = require("decache");
const supertest = require("supertest");
const sequelize = require("../../src/models");

const sinon = require("sinon");
const sandbox = sinon.createSandbox();
let agent;

const login = (anAgent, userCredentials) =>
    anAgent
        .post("/api/users/signIn")
        .send(userCredentials);

const logout = (anAgent) =>
    anAgent
        .post("/api/users/signOut");

describe("User endpoints", function () {
    this.beforeAll(async () => {

    });

    this.beforeEach(async () => {
        decache("../../src/app");
        decache("../../src/middlewares/captcha");

        const captcha = require("../../src/middlewares/captcha");

        sandbox
            .stub(captcha, "validateCaptcha")
            .callsFake(async (req, res, next) => {
                console.log("Validate Captcha FAKE");
                return next();
            });

        const app = require("../../src/app");
        agent = supertest.agent(app);
        await sequelize.sync({ force: true });


        const Customer = require("../../src/models/customer");
        const User = require("../../src/models/user");
        await Customer.create(
            {
                firstName: "Test",
                lastName: "Customer",
                user: {
                    email: "[email protected]",
                    password: "boo",
                },
            },
            {
                include: [User],
            }
        );
    });

    this.afterEach(async () => {
        sandbox.restore();
    });

    it("should create a new user", function (done) {
        agent
            .post("/api/users/signUp")
            .send({
                firstName: "firstName",
                lastName: "lastName",
                email: "[email protected]",
                password: "aPassword",
            })
            .expect(201)
            .end((err, res) => {
                err ? done(err) : done();
            });
    });

    it("should sign in", function (done) {
        login(agent, { email: "[email protected]", password: "boo" })
            .expect(200)
            .end((err, res) => {
                const { message, user } = res.body;
                message.should.be.equal("valid");
                user.should.have.property("email").equal("[email protected]");
                user.should.have.property("customer").have.property("firstName").equal("Test");
                user.should.have.property("customer").have.property("lastName").equal("Customer");

                agent
                    .get("/api/users/me")
                    .expect(200)
                    .end((err, res) => {
                        const user = res.body;
                        user.should.have.property("email").equal("[email protected]");
                        user.should.have.property("customer").have.property("firstName").equal("Test");
                        user.should.have.property("customer").have.property("lastName").equal("Customer");
                        err ? done(err) : done();
                    });
            });
    });

    it("should sign out", async function () {
        await login(agent, { email: "[email protected]", password: "boo" });
        await logout(agent)
            .expect(302)
            .expect("Location", "/");

        return agent
            .get("/api/users/me")
            .expect(401);
    });

    it("should return unauthorized", function (done) {
        agent
            .get("/api/users/me")
            .expect(401)
            .end((err, res) => {
                err ? done(err) : done();
            });
    });
});

์ด ๋ฌธ์ œ๋„๋ณด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์™œ ์ด๊ฒƒ์ด ๋‹ซํ˜€ ์žˆ์Šต๋‹ˆ๊นŒ?

๋ณต์› ๋™์ž‘์€ ์Šคํ…์„ ์„ค์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ํŠน์ • ๊ตฌ๋ฌธ์— ๋ฏผ๊ฐ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Afaik ๋‘ ๊ฐ€์ง€ ๋ชจ๋‘์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์œ ํšจํ•œ ๋ฐฉ๋ฒ•์ด์–ด์•ผํ•˜์ง€๋งŒ restore ()๋Š” ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ํ•˜๋‚˜์—์„œ๋Š” ์ž‘๋™ํ•˜๊ณ  ๋‹ค๋ฅธ ํ•˜๋‚˜์—์„œ๋Š” ์˜ˆ๊ธฐ์น˜ ์•Š์€ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

const sinon = require('sinon')

// restore does not work as expected

let db = {
  query: () => {
    return 'my query 1'
  }
}
const dbStub = sinon.stub().resolves('somejson')
db.query = dbStub
db.query() // somejson
sinon.restore()
db.query() // resolves nothing

// restore works as expected

db = {
  query: () => {
    return 'my query 1'
  }
}
sinon.stub(db, 'query').resolves('somejson')
db.query() // somejson
sinon.restore()
db.query() //my query 1

@scottpatrickwright db.query ์ง์ ‘ ํ• ๋‹น ํ•  ๋•Œ sinon ๋Š” ๋ณต์›ํ•ด์•ผ ํ•  ํ•ญ๋ชฉ์ด๋‚˜ ํ• ๋‹น ์ „์— ๊ฐ’์ด ๋ฌด์—‡์ธ์ง€ ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

@scottpatrickwright ์Šค๋ ˆ๋“œ์—์„œ ๋ถ„๋ช…ํžˆ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด ๋ฒ„๊ทธ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋‹ซํž™๋‹ˆ๋‹ค. ๊ท€ํ•˜์˜ ๊ฒฝ์šฐ์™€ ๊ฐ™์ด ์‚ฌ์šฉ์ž ์˜ค๋ฅ˜์˜€์Šต๋‹ˆ๋‹ค. ์„ค๋ช…๋˜๊ณ  ์˜๋„ ํ•œ๋Œ€๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. :-)

Sinon ์ƒŒ๋“œ ๋ฐ•์Šค๋Š” ์•Œ๊ณ ์žˆ๋Š” ์ •๋ณด๋ฅผ ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, Sinon์€ ์ƒํ˜ธ ์ž‘์šฉํ•˜๋Š” ๋Œ€์ƒ์— ๋Œ€ํ•œ ์ง€์‹์ด ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์œ„์—์„œ ์„ค๋ช…ํ•œ ์Šคํ…์€ ๋…๋ฆฝํ˜•์œผ๋กœ ๋งŒ๋“ค์–ด์ง‘๋‹ˆ๋‹ค. Sinon์€ ์‚ฌ์šฉ์ž๊ฐ€ ํ• ๋‹น ํ•œ ๊ฐœ์ฒด๋ฅผ ์ธ์‹ํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๋ฒˆ์งธ ์˜ˆ์—์„œ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค. sinon.replace(obj, fieldname, fake) ์„ (๋ฅผ) ์ˆ˜ํ–‰ํ•˜์—ฌ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. JavaScript ์ผ๋ฟ์ž…๋‹ˆ๋‹ค ๐Ÿ™‚

์ถฉ๋ถ„ํžˆ ๊ณตํ‰ํ•ฉ๋‹ˆ๋‹ค-์„ค๋ช… ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

2021 ๋…„ 2 ์›” 19 ์ผ ๊ธˆ์š”์ผ ์˜ค์ „ 7:02 Carl-Erik Kopseng [email protected]
์ผ๋‹ค :

@scottpatrickwright https://github.com/scottpatrickwright ํ์‡„๋˜์—ˆ์Šต๋‹ˆ๋‹ค
์Šค๋ ˆ๋“œ์—์„œ ๋ช…๋ฐฑํ•œ ๋ฒ„๊ทธ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ƒฅ
๊ท€ํ•˜์˜ ๊ฒฝ์šฐ์™€ ๊ฐ™์ด ์‚ฌ์šฉ์ž ์˜ค๋ฅ˜ : ์„ค๋ช… ๋ฐ ์˜๋„๋Œ€๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค :-)

Sinon ์ƒŒ๋“œ ๋ฐ•์Šค๋Š” ์•Œ๊ณ ์žˆ๋Š” ์ •๋ณด๋ฅผ ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” Sinon์ด
์ƒํ˜ธ ์ž‘์šฉํ•˜๋Š” ๋Œ€์ƒ์— ๋Œ€ํ•œ ์ง€์‹์„ ๊ฐ–์Šต๋‹ˆ๋‹ค. ์Šคํ… ๋‹น์‹ 
์œ„์˜ ์„ค๋ช…์€ ๋…๋ฆฝํ˜•์œผ๋กœ ๋งŒ๋“ค์–ด์ง‘๋‹ˆ๋‹ค. Sinon์€
ํ• ๋‹น ํ•œ ๊ฐœ์ฒด. ๋‘ ๋ฒˆ์งธ ์˜ˆ์—์„œ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค. ๋‹น์‹ ์€ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
๋˜ํ•œ sinon.replace (obj, fieldname, fake)๋ฅผ ์ˆ˜ํ–‰ํ•˜์—ฌ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค. ๊ทธ๋ƒฅ
์ž๋ฐ” ์Šคํฌ๋ฆฝํŠธ ๐Ÿ™‚

โ€”
๋‹น์‹ ์ด ์–ธ๊ธ‰ ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ๋ฐ›๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
์ด ์ด๋ฉ”์ผ์— ์ง์ ‘ ๋‹ต์žฅํ•˜๊ณ  GitHub์—์„œ ํ™•์ธํ•˜์„ธ์š”.
https://github.com/sinonjs/sinon/issues/2065#issuecomment-782032440 ๋˜๋Š”
๊ตฌ๋… ์ทจ์†Œ
https://github.com/notifications/unsubscribe-auth/AAKKRTFVMGEYVIB5GSIDXKTS7ZHMRANCNFSM4IGBASQQ
.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰