aws-sdk-mock - 模拟 s3.upload 不使用模拟实现
aws-sdk-mock - Mocking s3.upload is not using mock implementation
我正在使用这个包装函数将对象上传到 s3
// upload.js
async function uploadToS3 (body, bucket, key) {
console.log(`Uploading data to s3://${bucket}${key}`)
await s3
.upload({
Body: body,
Bucket: bucket,
Key: key
})
.promise()
.then((data) => {
console.log(`Successfully uploaded data to ${data.Location}`)
}
)
.catch((err) => {
console.error(err)
})
}
我正在尝试使用 aws-sdk-mock 来模拟该函数,因此当它被调用时它实际上不会将项目推送到 s3,我可以验证它正在记录成功还是失败。
这是我试过的
// upload.test.js
describe( 'uploadToS3', () => {
test('should upload a file to s3', async () => {
const body = 'test|data'
const bucket = 'testBucket'
const key = 'testKey'
AWS.mock( 'S3', 'upload',function (params, callback){
callback(null, 'successfully put item in s3');
});
await util.uploadToS3(body, bucket, key)
})
})
不幸的是,当我调用 uploadToS3
函数时,它仍然使用实际的 s3.upload 实现并尝试将对象发送到 S3。我已经成功地对其他 AWS 服务使用了类似的模拟方法,但这个方法似乎给我带来了问题。
如何模拟 AWS.S3.upload 函数以及后续的 .then
和 .catch
函数?
也许这可以用 Jest 代替?
您不需要使用 aws-sdk-mock
包。您可以使用 jest.mock(moduleName, factory, options) 方法自行模拟 aws-sdk
包。
例如
upload.js
:
import AWS from 'aws-sdk';
const s3 = new AWS.S3();
export async function uploadToS3(body, bucket, key) {
console.log(`Uploading data to s3://${bucket}${key}`);
await s3
.upload({
Body: body,
Bucket: bucket,
Key: key,
})
.promise()
.then((data) => {
console.log(`Successfully uploaded data to ${data.Location}`);
})
.catch((err) => {
console.error(err);
});
}
upload.test.js
:
import { uploadToS3 } from './upload';
import AWS from 'aws-sdk';
jest.mock('aws-sdk', () => {
const mockedS3 = {
upload: jest.fn().mockReturnThis(),
promise: jest.fn(),
};
return { S3: jest.fn(() => mockedS3) };
});
describe('uploadToS3', () => {
afterAll(() => {
jest.resetAllMocks();
});
afterEach(() => {
jest.clearAllMocks();
});
it('should upload file to s3', async () => {
const mockedS3 = new AWS.S3();
const logSpy = jest.spyOn(console, 'log');
mockedS3.promise.mockResolvedValueOnce({ Location: 'us' });
const body = 'test|data';
const bucket = 'testBucket';
const key = 'testKey';
await uploadToS3(body, bucket, key);
expect(mockedS3.upload).toBeCalledWith({ Body: body, Bucket: bucket, Key: key });
expect(mockedS3.promise).toBeCalledTimes(1);
expect(logSpy).toBeCalledWith('Successfully uploaded data to us');
});
it('should handle error when upload file to s3 failed', async () => {
const mockedS3 = new AWS.S3();
const errorLogSpy = jest.spyOn(console, 'error');
const mError = new Error('network');
mockedS3.promise.mockRejectedValueOnce(mError);
const body = 'test|data';
const bucket = 'testBucket';
const key = 'testKey';
await uploadToS3(body, bucket, key);
expect(mockedS3.upload).toBeCalledWith({ Body: body, Bucket: bucket, Key: key });
expect(mockedS3.promise).toBeCalledTimes(1);
expect(errorLogSpy).toBeCalledWith(mError);
});
});
单元测试结果:
PASS examples/67204024/upload.test.js (6.42 s)
uploadToS3
✓ should upload file to s3 (16 ms)
✓ should handle error when upload file to s3 failed (6 ms)
console.log
Uploading data to s3://testBuckettestKey
at console.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)
console.log
Successfully uploaded data to us
at console.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)
console.log
Uploading data to s3://testBuckettestKey
at console.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)
console.error
Error: network
at /Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/examples/67204024/upload.test.js:35:20
at Generator.next (<anonymous>)
at /Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/examples/67204024/upload.test.js:8:71
at new Promise (<anonymous>)
at Object.<anonymous>.__awaiter (/Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/examples/67204024/upload.test.js:4:12)
at Object.<anonymous> (/Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/examples/67204024/upload.test.js:32:70)
at Object.asyncJestTest (/Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
at /Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/node_modules/jest-jasmine2/build/queueRunner.js:45:12
at new Promise (<anonymous>)
at mapper (/Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
at /Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/node_modules/jest-jasmine2/build/queueRunner.js:75:41
at processTicksAndRejections (internal/process/task_queues.js:93:5)
16 | })
17 | .catch((err) => {
> 18 | console.error(err);
| ^
19 | });
20 | }
21 |
at console.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)
at examples/67204024/upload.js:18:15
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 6.896 s, estimated 7 s
这也是一个选项:
const getObjectStub = AWS.S3.prototype.getObject = Sinon.stub();
getObjectStub.yields(null, {
AcceptRanges: "bytes",
ContentLength: 3191,
ContentType: "image/jpeg",
Metadata: {
...
},
TagCount: 2,
VersionId: "null"
}
);
我正在使用这个包装函数将对象上传到 s3
// upload.js
async function uploadToS3 (body, bucket, key) {
console.log(`Uploading data to s3://${bucket}${key}`)
await s3
.upload({
Body: body,
Bucket: bucket,
Key: key
})
.promise()
.then((data) => {
console.log(`Successfully uploaded data to ${data.Location}`)
}
)
.catch((err) => {
console.error(err)
})
}
我正在尝试使用 aws-sdk-mock 来模拟该函数,因此当它被调用时它实际上不会将项目推送到 s3,我可以验证它正在记录成功还是失败。
这是我试过的
// upload.test.js
describe( 'uploadToS3', () => {
test('should upload a file to s3', async () => {
const body = 'test|data'
const bucket = 'testBucket'
const key = 'testKey'
AWS.mock( 'S3', 'upload',function (params, callback){
callback(null, 'successfully put item in s3');
});
await util.uploadToS3(body, bucket, key)
})
})
不幸的是,当我调用 uploadToS3
函数时,它仍然使用实际的 s3.upload 实现并尝试将对象发送到 S3。我已经成功地对其他 AWS 服务使用了类似的模拟方法,但这个方法似乎给我带来了问题。
如何模拟 AWS.S3.upload 函数以及后续的 .then
和 .catch
函数?
也许这可以用 Jest 代替?
您不需要使用 aws-sdk-mock
包。您可以使用 jest.mock(moduleName, factory, options) 方法自行模拟 aws-sdk
包。
例如
upload.js
:
import AWS from 'aws-sdk';
const s3 = new AWS.S3();
export async function uploadToS3(body, bucket, key) {
console.log(`Uploading data to s3://${bucket}${key}`);
await s3
.upload({
Body: body,
Bucket: bucket,
Key: key,
})
.promise()
.then((data) => {
console.log(`Successfully uploaded data to ${data.Location}`);
})
.catch((err) => {
console.error(err);
});
}
upload.test.js
:
import { uploadToS3 } from './upload';
import AWS from 'aws-sdk';
jest.mock('aws-sdk', () => {
const mockedS3 = {
upload: jest.fn().mockReturnThis(),
promise: jest.fn(),
};
return { S3: jest.fn(() => mockedS3) };
});
describe('uploadToS3', () => {
afterAll(() => {
jest.resetAllMocks();
});
afterEach(() => {
jest.clearAllMocks();
});
it('should upload file to s3', async () => {
const mockedS3 = new AWS.S3();
const logSpy = jest.spyOn(console, 'log');
mockedS3.promise.mockResolvedValueOnce({ Location: 'us' });
const body = 'test|data';
const bucket = 'testBucket';
const key = 'testKey';
await uploadToS3(body, bucket, key);
expect(mockedS3.upload).toBeCalledWith({ Body: body, Bucket: bucket, Key: key });
expect(mockedS3.promise).toBeCalledTimes(1);
expect(logSpy).toBeCalledWith('Successfully uploaded data to us');
});
it('should handle error when upload file to s3 failed', async () => {
const mockedS3 = new AWS.S3();
const errorLogSpy = jest.spyOn(console, 'error');
const mError = new Error('network');
mockedS3.promise.mockRejectedValueOnce(mError);
const body = 'test|data';
const bucket = 'testBucket';
const key = 'testKey';
await uploadToS3(body, bucket, key);
expect(mockedS3.upload).toBeCalledWith({ Body: body, Bucket: bucket, Key: key });
expect(mockedS3.promise).toBeCalledTimes(1);
expect(errorLogSpy).toBeCalledWith(mError);
});
});
单元测试结果:
PASS examples/67204024/upload.test.js (6.42 s)
uploadToS3
✓ should upload file to s3 (16 ms)
✓ should handle error when upload file to s3 failed (6 ms)
console.log
Uploading data to s3://testBuckettestKey
at console.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)
console.log
Successfully uploaded data to us
at console.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)
console.log
Uploading data to s3://testBuckettestKey
at console.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)
console.error
Error: network
at /Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/examples/67204024/upload.test.js:35:20
at Generator.next (<anonymous>)
at /Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/examples/67204024/upload.test.js:8:71
at new Promise (<anonymous>)
at Object.<anonymous>.__awaiter (/Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/examples/67204024/upload.test.js:4:12)
at Object.<anonymous> (/Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/examples/67204024/upload.test.js:32:70)
at Object.asyncJestTest (/Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
at /Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/node_modules/jest-jasmine2/build/queueRunner.js:45:12
at new Promise (<anonymous>)
at mapper (/Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
at /Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/node_modules/jest-jasmine2/build/queueRunner.js:75:41
at processTicksAndRejections (internal/process/task_queues.js:93:5)
16 | })
17 | .catch((err) => {
> 18 | console.error(err);
| ^
19 | });
20 | }
21 |
at console.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)
at examples/67204024/upload.js:18:15
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 6.896 s, estimated 7 s
这也是一个选项:
const getObjectStub = AWS.S3.prototype.getObject = Sinon.stub();
getObjectStub.yields(null, {
AcceptRanges: "bytes",
ContentLength: 3191,
ContentType: "image/jpeg",
Metadata: {
...
},
TagCount: 2,
VersionId: "null"
}
);