Local Testing of AWS Serverless Lambda Functions

Jens Knipper

  • Software Engineer
  • OpenValue Düsseldorf GmbH
  • curious about new technologies
  • likes well tested software!

Agenda

  • Testing of Microservices
  • Introduction to Lambda Functions
  • Lambdas vs. "classic" Microservices
  • Testing of Lambdas
  • Example Use-Case
  • Demo

Testing of Microservices

Database Adapter

Service Layer

Domain

External Service

External Database

HTTP Adapter

REST Adapter

Testing of Microservices

Unit-Tests

Database Adapter

Service Layer

Domain

External Service

External Database

HTTP Adapter

REST Adapter

Testing of Microservices

Integration-Tests

Database Adapter

Service Layer

Domain

External Service

External Database

HTTP Adapter

REST Adapter

Testing of Microservices

Component-Tests

Database Adapter

Service Layer

Domain

External Service

External Database

HTTP Adapter

REST Adapter

Testing of Microservices

Database Adapter

Service Layer

Domain

External Service

External Database

HTTP Adapter

REST Adapter

Summary

Testing of Microservices

Unit

Integration

Component

Manual

Summary

e2e

Unit

Introduction to Lambdas

  • simple function - very small!
    • e.g. no webserver needed
  • triggered by event
    • custom
    • AWS specific
      • e.g. fileupload to S3
  • runs your function only when needed
    • pay what you consume
    • no load - no lambda running
  • scales automatically
  • no state!

Lambdas vs. Microservices

Lambda Microservice
Webserver provided required
Endpoints one multiple
Scaling provided possible
Statefulness no possible
Size constrained growing with time

Testing of Lambdas

  • Lambdas can be Microservices!
    • testing should be the same!
  • same tools
    • Dependency Injection
    • Testcontainers
    • Wiremock
    • ...
  • new tools
    • Localstack

Example Use-Case

Example Use-Case

public class EventHandler implements RequestHandler<Input, Output> {
  private final EventHandlingService eventHandlingService;

  public EventHandler() {
    final S3Service s3Service = new S3Service(...);
    final ImageService imageService = new ImageService(...);
    
    this.eventHandlingService = new EventHandlingService(s3Service, imageService);
  }

  @Override
  public Output handleRequest(final Input input, final Context context) {
    return eventHandlingService.handleEvent(...);
  }

EventHandler

Example Use-Case

public class Input {
  private String bucket;
  private String key;
  
  ...
 }

Input & Output

public class Output {
  private String bucket;
  private String key;
  private String fileLink;
  
  ...
 }  

Example Use-Case

public class EventHandlingService {
  private final S3Service s3Service;
  private final ImageService imageService;

  public EventHandlingService(final S3Service s3Service, final ImageService imageService) {
    this.s3Service = s3Service;
    this.imageService = imageService;
  }

  public Output handleEvent(final String bucket, final String fileKey) {
    final InputStream inputStream = s3Service.getObject(...);
    ...
    final BufferedImage newImage = imageService.resize(...);
    ...
    final String link = s3Service.uploadFile(...);
    return new Output(...);
  }
}

EventHandlingService

Demo

Resources

Thank you!

Please ask questions.

jens@openvalue.de

@OpenValue

openvalue.eu