Skip to content

Commit 17e230b

Browse files
committed
test module
1 parent 593cbdb commit 17e230b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2181
-0
lines changed

aws-lambda-java-tests/README.md

+198
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
2+
# Tests utility
3+
4+
The `aws-lambda-java-tests` module provides opinionated tools to ease Java Lambda testing. This is a test dependency.
5+
6+
**Key features**
7+
8+
* Load events from json files and get them deserialized into Java Events.
9+
* Inject Events directly in JUnit 5 tests, using the `@ParameterizedTest` annotation.
10+
11+
12+
## Background
13+
14+
When using Java for a Lambda function, you must implement the RequestHandler interface and provide input and output types:
15+
16+
```java
17+
public interface RequestHandler<I, O> {
18+
public O handleRequest(I input, Context context);
19+
}
20+
```
21+
22+
The input is automatically deserialized by the Lambda Java Runtime from a json event into the type you define,
23+
and the output is serialized into JSON from the output type. More info in the [docs](https://docs.aws.amazon.com/lambda/latest/dg/java-handler.html).
24+
25+
When you want to test your Lambda function and your handleRequest method, you cannot simply use JSON events files
26+
as some of the event fields may not be deserialized correctly.
27+
28+
For example, an SQS JSON event contains a list of "Records", while the [`SQSEvent`](https://github.com/aws/aws-lambda-java-libs/blob/master/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/SQSEvent.java) use "records" with a lowercase.
29+
You can choose to modify the JSON input but it can be tedious and you generally want to keep the JSON event as you get it
30+
in the doc, the Lambda console or in your logs.
31+
32+
Now you can use the [aws-lambda-java-serialization](https://github.com/aws/aws-lambda-java-libs/tree/master/aws-lambda-java-serialization) module to deserialize events. And this test library is using this module as a dependency to ease tests of lambda function handlers.
33+
34+
## Installation
35+
36+
To install this utility, add the following dependency to your project. Note that it's a test dependency.
37+
38+
```xml
39+
<dependency>
40+
<groupId>com.amazonaws</groupId>
41+
<artifactId>aws-lambda-java-tests</artifactId>
42+
<version>1.0.0</version>
43+
<scope>test</scope>
44+
</dependency>
45+
```
46+
47+
Also have surefire in your plugins:
48+
49+
```xml
50+
<build>
51+
<plugins>
52+
<plugin>
53+
<groupId>org.apache.maven.plugins</groupId>
54+
<artifactId>maven-surefire-plugin</artifactId>
55+
<version>2.22.2</version>
56+
</plugin>
57+
</plugins>
58+
</build>
59+
```
60+
61+
## Usage
62+
63+
### Events injection
64+
65+
A set of annotations can be used to inject Events and/or to validate handler responses against those Events.
66+
**All those annotations must be used in conjunction with the [`@ParameterizedTest`](https://junit.org/junit5/docs/current/api/org.junit.jupiter.params/org/junit/jupiter/params/ParameterizedTest.html) annotation from Junit 5.**
67+
68+
`ParameterizedTest` enables to inject arguments into a unit test, so you can run the same test one or more time with different parameters.
69+
See [the doc](https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests) for more details on this.
70+
71+
**Event**
72+
73+
The `@Event` annotation permits to inject one Event into a Junit test.
74+
75+
Example:
76+
77+
```java
78+
// the json file must be in the classpath (most often in src/test/resources)
79+
@ParameterizedTest
80+
@Event(value = "sqs/sqs_event.json", type = SQSEvent.class)
81+
public void testInjectSQSEvent(SQSEvent event) {
82+
// test your handleRequest method with this event as parameter
83+
}
84+
```
85+
86+
**Events**
87+
88+
The `@Events` annotation permits to inject multiple Events into a Junit test
89+
90+
Examples:
91+
92+
```java
93+
@ParameterizedTest
94+
@Events(
95+
events = {
96+
@Event("sqs/sqs_event.json"),
97+
@Event("sqs/sqs_event2.json"),
98+
},
99+
type = SQSEvent.class
100+
)
101+
public void testInjectEvents(SQSEvent event) {
102+
// test your handleRequest method with all the JSON events available in the sqs folder
103+
}
104+
105+
// OR simpler
106+
107+
// sqs folder must be in the classpath (most often in src/test/resources)
108+
@ParameterizedTest
109+
@Events(folder = "sqs", type = SQSEvent.class)
110+
public void testInjectEventsFromFolder(SQSEvent event) {
111+
// test your handleRequest method with all the JSON events available in the sqs folder
112+
}
113+
```
114+
115+
**HandlerParams**
116+
117+
The `@HandlerParams` is the most advanced one as it permits to provide both input and output as arguments to your tests.
118+
Thus you can validate your `handlerRequest` method by providing the output and asserting on the expected output.
119+
120+
```java
121+
122+
// Single event
123+
@ParameterizedTest
124+
@HandlerParams(
125+
event = @Event(value = "apigw/events/apigw_event.json", type = APIGatewayProxyRequestEvent.class),
126+
response = @Response(value = "apigw/responses/apigw_response.json", type = APIGatewayProxyResponseEvent.class))
127+
public void testSingleEventResponse(APIGatewayProxyRequestEvent event, APIGatewayProxyResponseEvent response) {
128+
}
129+
130+
// Multiple events in folder
131+
@ParameterizedTest
132+
@HandlerParams(
133+
events = @Events(folder = "apigw/events/", type = APIGatewayProxyRequestEvent.class),
134+
responses = @Responses(folder = "apigw/responses/", type = APIGatewayProxyResponseEvent.class))
135+
public void testMultipleEventsResponsesInFolder(APIGatewayProxyRequestEvent event, APIGatewayProxyResponseEvent response) {
136+
}
137+
138+
// Multiple events
139+
@HandlerParams(
140+
events = @Events(
141+
events = {
142+
@Event("apigw/events/apigw_event.json"),
143+
@Event("apigw/events/apigw_event2.json"),
144+
},
145+
type = APIGatewayProxyRequestEvent.class
146+
),
147+
responses = @Responses(
148+
responses = {
149+
@Response("apigw/responses/apigw_response.json"),
150+
@Response("apigw/responses/apigw_response2.json")
151+
},
152+
type = APIGatewayProxyResponseEvent.class
153+
)
154+
)
155+
public void testMultipleEventsResponses(APIGatewayProxyRequestEvent event, APIGatewayProxyResponseEvent response) {
156+
}
157+
```
158+
159+
If you cannot use those annotations (for example if you use TestNG), or if you want to load the events on your own, you can directly use the `EventLoader`, which is the underlying class that load the json events.
160+
161+
### EventLoader
162+
163+
`EventLoader` enables to load any Event from a JSON file and deserialize it into a Java Object.
164+
Either one from the [aws-lambda-java-events](https://github.com/aws/aws-lambda-java-libs/tree/master/aws-lambda-java-events) library
165+
or your own Event.
166+
167+
EventLoader provides a load method for most of the pre-defined events:
168+
169+
```java
170+
APIGatewayV2HTTPEvent httpEvent =
171+
EventLoader.loadApiGatewayHttpEvent("apigw_http_event.json");
172+
173+
APIGatewayProxyRequestEvent restEvent =
174+
EventLoader.loadApiGatewayRestEvent("apigw_rest_event.json");
175+
176+
DynamodbEvent ddbEvent = EventLoader.loadDynamoDbEvent("ddb_event.json");
177+
178+
KinesisEvent kinesisEvent =
179+
EventLoader.loadKinesisEvent("kinesis_event.json");
180+
181+
ScheduledEvent eventBridgeEvent =
182+
EventLoader.loadScheduledEvent("eb_event.json");
183+
184+
S3Event s3Event = EventLoader.loadS3Event("s3_event.json");
185+
186+
SNSEvent snsEvent = EventLoader.loadSNSEvent("sns_event.json");
187+
188+
SQSEvent sqsEvent = EventLoader.loadSQSEvent("sqs_event.json");
189+
190+
// ... and many others
191+
```
192+
193+
Or you can load what you prefer with the generic method:
194+
195+
```java
196+
MyEvent myEvent = EventLoader.loadEvent("my_event.json", MyEvent.class);
197+
```
198+

aws-lambda-java-tests/pom.xml

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
5+
<groupId>com.amazonaws</groupId>
6+
<artifactId>aws-lambda-java-tests</artifactId>
7+
<version>1.0.0</version>
8+
<packaging>jar</packaging>
9+
10+
<name>AWS Lambda Java Tests</name>
11+
<description>Testing module for the AWS Lambda Java Runtime</description>
12+
<url>https://aws.amazon.com/lambda/</url>
13+
<licenses>
14+
<license>
15+
<name>Apache License, Version 2.0</name>
16+
<url>https://aws.amazon.com/apache2.0</url>
17+
<distribution>repo</distribution>
18+
</license>
19+
</licenses>
20+
<scm>
21+
<url>https://github.com/aws/aws-lambda-java-libs.git</url>
22+
</scm>
23+
<developers>
24+
<developer>
25+
<name>AWS Lambda team</name>
26+
<organization>Amazon Web Services</organization>
27+
<organizationUrl>https://aws.amazon.com/</organizationUrl>
28+
</developer>
29+
</developers>
30+
31+
<properties>
32+
<maven.compiler.source>1.8</maven.compiler.source>
33+
<maven.compiler.target>1.8</maven.compiler.target>
34+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
35+
<junit.version>5.7.0</junit.version>
36+
</properties>
37+
38+
<dependencies>
39+
<dependency>
40+
<groupId>com.amazonaws</groupId>
41+
<artifactId>aws-lambda-java-serialization</artifactId>
42+
<version>1.0.0</version>
43+
</dependency>
44+
<dependency>
45+
<groupId>com.amazonaws</groupId>
46+
<artifactId>aws-lambda-java-events</artifactId>
47+
<version>3.6.0</version>
48+
</dependency>
49+
<dependency>
50+
<groupId>org.junit.jupiter</groupId>
51+
<artifactId>junit-jupiter-api</artifactId>
52+
<version>${junit.version}</version>
53+
</dependency>
54+
<dependency>
55+
<groupId>org.junit.jupiter</groupId>
56+
<artifactId>junit-jupiter-engine</artifactId>
57+
<version>${junit.version}</version>
58+
</dependency>
59+
<dependency>
60+
<groupId>org.junit.jupiter</groupId>
61+
<artifactId>junit-jupiter-params</artifactId>
62+
<version>${junit.version}</version>
63+
</dependency>
64+
<dependency>
65+
<groupId>org.apache.commons</groupId>
66+
<artifactId>commons-lang3</artifactId>
67+
<version>3.11</version>
68+
</dependency>
69+
70+
<dependency>
71+
<groupId>org.assertj</groupId>
72+
<artifactId>assertj-core</artifactId>
73+
<version>3.18.1</version>
74+
<scope>test</scope>
75+
</dependency>
76+
</dependencies>
77+
78+
<build>
79+
<plugins>
80+
<plugin>
81+
<groupId>org.apache.maven.plugins</groupId>
82+
<artifactId>maven-compiler-plugin</artifactId>
83+
<version>3.8.1</version>
84+
<configuration>
85+
<source>${maven.compiler.source}</source>
86+
<target>${maven.compiler.target}</target>
87+
<useIncrementalCompilation>false</useIncrementalCompilation>
88+
</configuration>
89+
</plugin>
90+
<plugin>
91+
<groupId>org.apache.maven.plugins</groupId>
92+
<artifactId>maven-surefire-plugin</artifactId>
93+
<version>2.22.2</version>
94+
</plugin>
95+
</plugins>
96+
</build>
97+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. */
2+
package com.amazonaws.services.lambda.runtime.tests;
3+
4+
import com.amazonaws.services.lambda.runtime.tests.annotations.Event;
5+
import org.junit.jupiter.api.extension.ExtensionContext;
6+
import org.junit.jupiter.params.provider.Arguments;
7+
import org.junit.jupiter.params.provider.ArgumentsProvider;
8+
import org.junit.jupiter.params.support.AnnotationConsumer;
9+
10+
import java.util.stream.Stream;
11+
12+
/**
13+
* Used to process @{@link Event} com.amazonaws.services.lambda.runtime.tests.annotations
14+
*/
15+
public class EventArgumentsProvider implements ArgumentsProvider, AnnotationConsumer<Event> {
16+
17+
private Event event;
18+
19+
@Override
20+
public Stream<? extends Arguments> provideArguments(ExtensionContext extensionContext) {
21+
Object o = EventLoader.loadEvent(event.value(), event.type());
22+
return Stream.of(Arguments.of(o));
23+
}
24+
25+
@Override
26+
public void accept(Event event) {
27+
this.event = event;
28+
}
29+
}

0 commit comments

Comments
 (0)