0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

lambda + typescript + s3のリファクタリングをしてテストケースを書いたメモ

Last updated at Posted at 2021-03-28

概要

前回はS3をローカルで立ち上げた。
今回は、ローカル環境でLambda+S3のテストをするを参考に、リファクタリングをしてテストを行う。

ソースコード

構造

src
  - lambda
    - handlers
      - s3-sample.ts
    - service
      - s3-sample.ts
test
  - fixture
    - s3
      - message.txt
  - lambda
    - service
      - s3-sample.test.ts

ソース

  • 処理をgetS3Objectに移し、インスタンスを作って渡すようにする。
src/lambda/hendler/s3-sample.ts
import { S3 } from 'aws-sdk';
import { Handler } from 'aws-lambda';
import { getS3Object } from '../service/s3-sample';

const s3 = new S3();
const { S3_BUCKET } = process.env;
if (!S3_BUCKET) throw Error('env S3_BUCKET is empy')

export const lambdaHandler: Handler = async (event, context, callback) => {
  try {
    const message = getS3Object({ s3, key: event.Key, bucket: S3_BUCKET, callback });
    console.log(message)
  } catch (err) {
    console.log(err);
    return err;
  }
};
  • getS3Objectでは、使用するインスタンスは外部から受け取る。DI。
src/lambda/service/s3-sample.ts
import type { S3 } from 'aws-sdk';
import { Callback } from 'aws-lambda';
interface Payload {
  s3: S3
  key: string
  bucket: string
  callback: Callback
}
export const getS3Object: (o: Payload) => Promise<string> = async ({ s3, bucket, key, callback }) => {
  const params = {
    Bucket: bucket,
    Key: key
  };
  const ret = await s3.getObject(params).promise();
  if (!ret.Body) throw Error(`s3 object is empty. Bucket: ${bucket}, Key: ${key}`)
  const message = ret.Body.toString();
  console.log(message);
  callback(null, `access ${key}`)
  return message;
}
  • テストではs3オブジェクトを作成して渡してやる。
test/lambda/service/s3-sample.test.ts
import * as fs from 'fs';
import * as path from 'path';
import { S3 } from 'aws-sdk';
import { getS3Object } from '@/lambda/service/s3-sample';
// localstack
const config = {
  endpoint: 'http://localhost:4566',
  s3ForcePathStyle: true,
};

const s3 = new S3(config);

/*
 * test suits
 */
describe('core/getS3Object test suit #1', () => {
  // shared variables over the test suit
  let bucket: string;
  let key: string;
  const callback = () => { }

  /*
   * starup
  */
  beforeEach(async () => {
    // generate test resource sequence code from timestamp
    const now = new Date().getTime();
    bucket = `test-bucket-${now}`;
    key = `message_${now}.txt`;
    // create bucket & bucket key
    await s3.createBucket({ Bucket: bucket }).promise();
    await s3.putObject({
      Bucket: bucket,
      Key: key,
      ContentType: 'text/plain',
      Body: fs.readFileSync(path.join(__dirname, '..', '..', 'fixture', 's3', 'message.txt')),
    }).promise();
  });

  /*
   * test cases
  */
  it('successfully get an object from S3 bucket', async () => {
    const message = await getS3Object({ s3, bucket, key, callback });
    expect(message).toBe('Hi, there.\n');
  });

  it('throw error if access to non-existent key', async () => {
    try {
      await getS3Object({ s3, bucket, key: 'non-existent', callback })
      fail()
    } catch (error) {
      expect(error.name).toBe('NoSuchKey');
      expect(error.message).toBe('The specified key does not exist.');
    }
  });

  it('throw error if access to non-existent bucket', async () => {
    try {
      await getS3Object({ s3, bucket: 'non-existent', key: 'non-existent', callback })
      fail()
    } catch (error) {
      expect(error.name).toBe('NoSuchBucket');
      expect(error.message).toBe('The specified bucket does not exist');
    }

  });

  /*
   * tear-down
   */
  afterEach(async () => {
    // delete bucket key & bucket
    await s3.deleteObject({
      Bucket: bucket,
      Key: key,
    }).promise();
    await s3.deleteBucket({ Bucket: bucket }).promise();
  });
});

参考

Testable - lambda : 和田卓人
ローカル環境でLambda+S3のテストをする
github aws-sam-localstack-example
DI・DIコンテナ、ちゃんと理解出来てる・・?

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?