如果从另一个模块调用该模块,为什么突变一个模块会更新引用,而从另一个模块调用则不会更新? [英] Why does mutating a module update the reference if calling that module from another module, but not if calling from itself?

查看:154
本文介绍了如果从另一个模块调用该模块,为什么突变一个模块会更新引用,而从另一个模块调用则不会更新?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此问题与测试javascript和模拟功能有关.

This question pertains to testing javascript and mocking functions.

说我有一个看起来像这样的模块:

Say I have a module that looks like this:

export function alpha(n) {
    return `${n}${beta(n)}${n}`;
}

export function beta(n) {
    return new Array(n).fill(0).map(() => ".").join("");
}

然后我无法通过以下方式对其进行测试:

Then I can't test it the following way:

import * as indexModule from "./index";

//Not what we want to do, because we want to mock the functionality of beta
describe("alpha, large test", () => {
    it("alpha(1) returns '1.1'", () => {
        expect(indexModule.alpha(1)).toEqual("1.1"); //PASS
    });

    it("alpha(3) returns '3...3'", () => {
        expect(indexModule.alpha(3)).toEqual("3...3"); //PASS
    });
});

//Simple atomic test
describe("beta", () => {
    it("beta(3) returns '...'", () => {
        expect(indexModule.beta(3)).toEqual("..."); //FAIL: received: 'x'
    });
});

//Here we are trying to mutate the beta function to mock its functionality
describe("alpha", () => {

    indexModule.beta = (n) => "x";
    it("works", () => {
        expect(indexModule.alpha(3)).toEqual("3x3"); //FAIL, recieved: '3...3'
    });
});

但是,如果将模块分成两个部分:

However, if split the module into two:

alpha.js

import { beta } from "./beta";

export function alpha(n) {
    return `${n}${beta(n)}${n}`;
}

beta.js

export function beta(n) {
    return new Array(n).fill(0).map(() => ".").join("");
}

然后我可以更改beta模块,而alpha知道它:

Then I can mutate the beta module, and alpha knows about it:

import { alpha } from "./alpha";
import * as betaModule from "./beta";

describe("alpha", () => {
    betaModule.beta = (n) => "x";
    it("works", () => {
        expect(alpha(3)).toEqual("3x3");   //PASS
    });
});

为什么会这样?我正在寻找技术上特定的答案.

Why is this the case? I'm looking for a technically specific answer.

我有一个Github分支,其代码为此处,请参见mutateModulesingleFunctionPerModuleAndMutate文件夹.

I have a Github branch with this code here, see the mutateModule and singleFunctionPerModuleAndMutate folders.

另一个问题-在本示例中,我通过直接重新分配属性来对模块进行变异.我理解使用Jest模拟功能本质上会做同样的事情是对的吗?

As an additional question - in this example I am mutating the module by directly reassigning properties. Am I right in understanding that using jest mock functionality is going to be essentially doing the same thing?

即.如果第一个示例不起作用而第二个示例不起作用的原因是由于该突变,那么它恰到好处地意味着使用jest模块的模拟功能同样无法正常工作.

ie. If the reason that the first example doesn't work but the second doesn't is due to the mutation, then it necceserily means that using the jest module mocking functions is similarly not going to work.

据我所知-在测试模块时无法模拟模块中的单个功能,

As far as I know - there is not way to mock a single function in a module, while testing that module, as this jest github issues talks about. What I'm wanting to know - is why this is.

推荐答案

如果从另一个模块中调用该模块,而从自身中调用则为什么不更新一个模块,为什么更新该引用呢?

Why does mutating a module update the reference if calling that module from another module, but not if calling from itself?

在ES6中,导入是有关导出值的实时只读视图" .

导入ES6模块时,您实际上可以获得该模块导出的内容的实时视图.

When you import an ES6 module you essentially get a live view of what is exported by that module.

实时视图可以更改,任何导入模块导出实时视图的代码都可以看到该变化.

The live view can be mutated, and any code that imports a live view of the module exports will see the mutation.

这就是为什么当alphabeta在两个不同的模块中时测试可以工作的原因.该测试修改了beta模块的实时视图,并且由于alpha模块使用了beta模块的实时视图,因此它会自动使用模拟功能而不是原始功能.

That is why your test works when alpha and beta are in two different modules. The test modifies the live view of the beta module, and since the alpha module uses the live view of the beta module, it automatically uses the mocked function instead of the original.

另一方面,在alphabeta上面的代码中,在同一模块中,并且 alpha直接调用beta . alpha 不使用模块的实时视图,因此当测试修改模块的实时视图时,它将无效.

On the other hand, in the code above alpha and beta are in the same module and alpha calls beta directly. alpha does not use the live view of the module so when the test modifies the live view of the module it has no effect.

另一个问题-在本示例中,我通过直接重新分配属性来对模块进行变异.我理解使用Jest模拟功能本质上会做相同的事情,对吗?

As an additional question - in this example I am mutating the module by directly reassigning properties. Am I right in understanding that using jest mock functionality is going to be essentially doing the same thing?

有几种方法可以使用Jest进行模拟.

There are a few ways to mock things using Jest.

其中一种方法是使用 jest.spyOn 对象和方法名称以及使用调用原始方法的间谍将方法替换在对象上.

One of the ways is using jest.spyOn which accepts an object and a method name and replaces the method on the object with a spy that calls the original method.

使用jest.spyOn的一种常见方法是将ES6模块的实时视图作为对象传递给它,从而使该模块的实时视图发生变化.

A common way to use jest.spyOn is to pass it the live view of an ES6 module as the object which mutates the live view of the module.

是的,可以通过将ES6模块的实时视图传递给类似jest.spyOn的东西来模拟(或 spyOn (来自Jasmine),或

So yes, mocking by passing the live view of an ES6 module to something like jest.spyOn (or spyOn from Jasmine, or sinon.spy from Sinon, etc.) mutates the live view of the module in essentially the same way as directly mutating the live view of the module like you are doing in the code above.

据我所知-测试模块时,无法在模块中模拟单个函数,正如github问题所谈论的那样.我想知道的-这就是为什么.

As far as I know - there is not way to mock a single function in a module, while testing that module, as this jest github issues talks about. What I'm wanting to know - is why this is.

实际上,这是有可能的.

Actually, it is possible.

"ES6模块自动支持循环依赖" ,这意味着模块的实时视图可以导入到模块本身中.

只要alpha使用定义了beta的模块的实时视图调用beta,即可在测试期间模拟beta.即使它们是在同一模块中定义的,它也可以工作:

As long as alpha calls beta using the live view of the module that beta is defined in, then beta can be mocked during the test. This works even if they are defined in the same module:

import * as indexModule from './index'  // import the live view of the module

export function alpha(n) {
    return `${n}${indexModule.beta(n)}${n}`;  // call beta using the live view of the module
}

export function beta(n) {
    return new Array(n).fill(0).map(() => ".").join("");
}

这篇关于如果从另一个模块调用该模块,为什么突变一个模块会更新引用,而从另一个模块调用则不会更新?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆