Поддельные серверы Sinon - это то, что вы можете использовать для разработки клиента, который сам выполняет запросы, вместо оболочки вокруг существующего клиента, такого как AWS.S3
, как вы делаете.В этом случае лучше просто заглушить поведение AWS.S3
, а не проверять фактические запросы, которые он делает.Таким образом, вы можете избежать тестирования деталей реализации AWS.S3
.
Поскольку вы используете TypeScript и сделали свой клиент s3 private
, вам нужно будет внести некоторые изменения, чтобы выставитьэто к вашим тестам.В противном случае вы не сможете заглушить его методы без жалоб компилятора TS.Вы также не сможете писать утверждения с использованием объекта params
по тем же причинам.
Поскольку я не использую TS регулярно, я не слишком знаком с его распространенными методами внедрения зависимостей, ноодна вещь, которую вы можете сделать, это добавить необязательные аргументы конструктора в ваш класс S3Uploader
, который может перезаписывать свойства s3
и arguments
по умолчанию, например:
constructor(s3, params) {
if (s3) this.s3 = s3;
if (params) this.params = params;
}
После чего вы можете создать заглушкуи передайте его в свой тестовый экземпляр следующим образом:
const s3 = sinon.createStubInstance(AWS.S3);
const params = { foo: 'bar' };
const uploader = new S3Uploader(s3, params);
После того, как у вас есть экземпляр заглушки, вы можете написать подтверждений , чтобы убедиться, что метод upload
был названтак, как вы хотите:
sinon.assert.calledOnce(s3.upload);
sinon.assert.calledWith(s3.upload, sinon.match.same(params), sinon.match.func);
Вы также можете повлиять на поведение метода upload
, используя sinon stub api .Например, чтобы заставить его потерпеть неудачу, вот так:
s3.upload.callsArgWith(1, null);
Или сделайте так, чтобы он был успешным, вот так:
const data = { whatever: 'data', you: 'want' };
s3.upload.callsArgWith(1, null, data);
Вы, вероятно, захотите совершенно отдельный тест для каждого из этих случаев,используя экземпляр before
ловушку, чтобы избежать дублирования общих настроек.Тестирование на успех будет включать просто await
обещание и проверку того, что его результатом являются данные.Тестирование на сбой будет включать try/catch
, который гарантирует, что обещание было отклонено с соответствующей ошибкой.
Кроме того, поскольку вы, похоже, выполняете здесь реальные модульные тесты, я рекомендую протестировать каждый метод S3Uploader отдельно вместо того, чтобы называть их всех в один большой тест.Это значительно сокращает количество возможных случаев, которые вам нужно охватить, делая ваши тесты намного проще.Примерно так:
@suite
class S3UploaderTest {
params: any; // Not sure the best way to type this.
s3: any; // Same. Sorry, not too experienced with TS.
uploader: S3Uploader | undefined;
before() {
this.params = {};
this.s3 = sinon.createStubInstance(AWS.S3);
this.uploader = new S3Uploader(this.s3, this.params);
}
@test
"send should set Body param and return instance"() {
const stream = "HalloWelt";
const result = this.uploader.send(stream);
Chai.expect(this.params.Body).to.equal(stream);
Chai.expect(result).to.equal(this.uploader);
}
@test
"toBucket should set Bucket param and return instance"() {
const bucket = "onetimeupload.test"
const result = this.uploader.toBucket(bucket);
Chai.expect(this.params.Bucket).to.equal(bucket);
Chai.expect(result).to.equal(this.uploader);
}
@test
"toFolder should set Key param and return instance"() {
const path = "onetimeupload.test"
const result = this.uploader.toFolder(path);
Chai.expect(this.params.Key).to.equal(path);
Chai.expect(result).to.equal(this.uploader);
}
@test
"upload should attempt upload to s3"() {
this.uploader.upload();
sinon.assert.calledOnce(this.s3.upload);
sinon.assert.calledWith(
this.s3.upload,
sinon.match.same(this.params),
sinon.match.func
);
}
@test
async "upload should resolve with response if successful"() {
const data = { foo: 'bar' };
s3.upload.callsArgWith(1, null, data);
const result = await this.uploader.upload();
Chai.expect(result).to.equal(data);
}
@test
async "upload should reject with error if not"() {
const error = new Error('Test Error');
s3.upload.callsArgWith(1, error, null);
try {
await this.uploader.upload();
throw new Error('Promise should have rejected.');
} catch(err) {
Chai.expect(err).to.equal(err);
}
}
}
Если бы я делал это с собственно мокко, я бы сгруппировал тесты каждого метода во вложенный блок describe
.Я не уверен, поощряется ли это или даже возможно с mocha-typescript
, но если это так, вы можете рассмотреть это.