但我对西农在台面下是如何工作仍有一些疑问。我想我是在说Sinon,但这个问题可能适用于所有其他设计为mock/stub/spy的库。
在过去的几年里,我工作最多的语言是Java。在Java中,我使用Mockito来模拟/存根依赖项和依赖项注入。我曾经导入这个类,用@mock
注释这个字段,并将这个mock作为param传递给被测试的类。对我来说,很容易看出我在做什么:模仿一个类,并将模仿作为param传递。
当我第一次开始使用SinonJS时,我看到了这样的情况:
moduleundertest.spec.js
const request = require('request')
describe('Some tests', () => {
let requestStub
beforeEach(() => {
requestStub = sinon.stub(request, 'get')
})
afterEach(() => {
request.get.restore()
})
it('A test case', (done) => {
const err = undefined
const res = { statusCode: 200 }
const body = undefined
requestStub
.withArgs("some_url")
.yields(err, res, body)
const moduleUnderTest = moduleUnderTest.someFunction()
// some assertions
})
})
moduleundertest.js
const request = require('request')
// some code
request
.get("some_url", requestParams, onResponse)
而且管用。当我们运行测试时,实现moduleundertest.js
中的request
调用request
模块的stubbed版本。
我尝试了Sinon repo中stub.js
代码中的逻辑,但我对JavaScript还不是很熟悉。抱歉这篇文章太长了,如果这是一个假问题,我很抱歉。:)
如果我们不将stubbed对象作为param传递(注入),Sinon(和其他mock/stub/spy库)如何使实现调用stub?
让我们自己编写简单的stubbing util,好吗?
为了简洁起见,它非常有限,没有提供stubbing API,每次只返回42。但这应该足以说明Sinon是如何工作的。
function stub(obj, methodName) {
// Get a reference to the original method by accessing
// the property in obj named by methodName.
var originalMethod = obj[methodName];
// This is actually called on obj.methodName();
function replacement() {
// Always returns this value
return 42;
// Note that in this scope, we are able to call the
// orignal method too, so that we'd be able to
// provide callThrough();
}
// Remember reference to the original method to be able
// to unstub (this is *one*, actually a little bit dirty
// way to reference the original function)
replacement.originalMethod = originalMethod;
// Assign the property named by methodName to obj to
// replace the method with the stub replacement
obj[methodName] = replacement;
return {
// Provide the stub API here
};
}
// We want to stub bar() away
var foo = {
bar: function(x) { return x * 2; }
};
function underTest(x) {
return foo.bar(x);
}
stub(foo, "bar");
// bar is now the function "replacement"
// foo.bar.originalMethod references the original method
underTest(3);
Sinon在测试执行期间替换整个请求模块
(或部分),使存根通过require('request')
可用,然后在测试完成后恢复它?
require('request')
将返回在每次调用“request”模块中创建的相同的(对象)引用。
请参见NodeJS文档:
模块在第一次加载后缓存。这意味着(除其他外)对require('foo')
的每次调用都将返回完全相同的对象,如果它将解析为相同的文件。
多次调用require('foo')
可能不会导致多次执行模块代码。这是一个重要的特点。使用它,可以返回“部分完成”的对象,从而允许在传递依赖项会导致循环的情况下加载传递依赖项。
如果它还没有变得清楚:它只替换从“requested”模块返回的对象引用的一个方法,它不会替换该模块。
这就是为什么你不打电话
stub(obj.method)
因为这只传递对函数方法
的引用。Sinon将无法更改对象obj
。
文件还说:
如果您想让一个模块多次执行代码,那么导出一个函数,并调用该函数。
这意味着,如果模块如下所示:
module.exports = function() {
return {
// New object everytime the required "factory" is called
};
};
// The function returned by require("foo") does not change
const moduleFactory = require("./foo"),
// This will change on every call
newFooEveryTime = moduleFactory();
这样的模块工厂函数不能存根,因为您不能从模块内替换require()
导出的函数。
在Java中,我使用Mockito来模拟/存根依赖项和依赖项注入。我曾经导入这个类,用@mock
注释这个字段,并将这个mock作为param传递给被测试的类。对我来说,很容易看出我在做什么:模仿一个类,并将模仿作为param传递。
在Java中,您(没有任何东西)不能将一个方法重新分配到一个新的值,这是不能做到的。取而代之的是生成新的字节码,使mock提供与mocked类相同的接口。与Sinon相反,在Mockito中,所有的方法都被嘲笑,并且应该被明确地指示调用真正的方法。
Mockito将有效地调用mock()
,并最终将结果分配给带注释的字段。
但是您仍然需要将模拟替换/分配给被测试类中的一个字段,或者将它传递给一个被测试的方法,因为模拟本身没有帮助。
@Mock
Type field;
或
Type field = mock(Type.class)
var myAPI = { method: function () {} };
var mock = sinon.mock(myAPI);
mock.expects("method").once().throws();
wrapMethod(this.object, method, function () {
return mockObject.invokeMethod(method, this, arguments);
});
Java的switch语句是如何工作的?它如何将所使用变量的值与案例部分中给出的值进行比较?它是否使用或,还是完全是其他原因? 我主要对1.7之前的版本感兴趣。
除了阅读github中的代码之外,是否有关于signalr.redis包如何工作的白皮书类型的文档?具体地说,我想知道它为Redis添加了哪些键、更新/删除策略等。当查看Redis内部时,我只看到以下调用中指定的一个键(即“signalr.Redis.sample”): 这把钥匙好像是Redis的柜台。我假设正在创建其他键并迅速删除,以方便连接到Redis的每个应用服务器之间的消息。
@Component表示给定的类将是给定上下文中的单例,@aspect表示在运行时/编译期间,一个方面类的内容将以某种方式编织到目标类中--例如,这个目标类不是单例而是原型。我最后的结局是什么?
此函数生成数组的排列。我已经把笔放在纸上,在开发工具中放置断点,并煞费苦心地逐步完成每个函数调用,但我仍然不明白这是如何工作的。 具体来说,就是 for 循环。一旦 do It 函数拼接了数组中的所有数字,它将临时数组的切片副本推送到答案数组中。然后,它将项拼接到参数数组中,从临时数组中弹出相同的项,并返回 for 循环第一次迭代的答案。因此,在遍历数组一次后,答案 = [1,2,3] 温度 =
新的Java17型模式匹配开关如何在引擎盖下工作?由于该功能相当新,本问题不讨论它。 提醒:要使此代码在Java 17下工作,需要启用预览功能 使用javap-c对上述代码进行了反汇编: 鉴于这一关键点: 看起来Java在自动生成的int-typeSwitch(object,int)方法中将对象转换为int,我看不到生成的代码。这种转换的目标是能够在int值上使用常规的切换表。 起初,我认为使用了
问题内容: 在阅读了戴夫·切尼(Dave Cheney)关于Go的地图的博客文章之后,对我来说,还有几件事尚不清楚。 TLDR: 为什么它们无序? 实际值存储在哪里? 深入研究运行时程序包后,我发现基本的映射结构如下: -是存储区数组,其中索引是键的哈希值的低位,其中存储区为: ..好吧,这只是每个项目是键的哈希值的第一个字节的数组。键值对存储为(每个存储桶八对)。但是到底在哪里?考虑到映射可能包