+++ title = "Validation Tests" weight = 300 +++ ### Validation Tests Sometimes we want the inputs to be configurable, but we also want to put constraints on those inputs or validate that the input is valid. Suppose for the `HitCounter` construct we want to allow the user to specify the `readCapacity` on the DynamoDB table, but we also want to ensure the value is within a reasonable range. We can write a test to make sure that the validation logic works: pass in invalid values and see what happens. First, add a `readCapacity` property to `HitCounterProps`: Edit `HitCounterProps.java` {{}} package com.myorg; import software.amazon.awscdk.services.lambda.IFunction; public interface HitCounterProps { // Public constructor for the props builder public static Builder builder() { return new Builder(); } // The function for which we want to count url hits IFunction getDownstream(); Number getReadCapacity(); // The builder for the props interface public static class Builder { private IFunction downstream; private Number readCapacity; public Builder downstream(final IFunction function) { this.downstream = function; return this; } public Builder readCapacity(final Number readCapacity) { this.readCapacity = readCapacity; return this; } public HitCounterProps build() { if(this.downstream == null) { throw new NullPointerException("The downstream property is required!"); } return new HitCounterProps() { @Override public IFunction getDownstream() { return downstream; } @Override public Number getReadCapacity() { return readCapacity; } }; } } } {{}} Then update the DynamoDB table resource to add the `readCapacity` property. {{}} Number readCapacity = (props.getReadCapacity() == null) ? 5 : props.getReadCapacity(); this.table = Table.Builder.create(this, "Hits") .partitionKey(Attribute.builder() .name("path") .type(AttributeType.STRING) .build()) .encryption(TableEncryption.AWS_MANAGED) .readCapacity(readCapacity) .build(); {{}} Now add a validation which will throw an error if the readCapacity is not in the allowed range. {{}} public class HitCounter extends Construct { private final Function handler; private final Table table; public HitCounter(final Construct scope, final String id, final HitCounterProps props) throws RuntimeException { super(scope, id); if (props.getReadCapacity() != null) { if (props.getReadCapacity().intValue() < 5 || props.getReadCapacity().intValue() > 20) { throw new RuntimeException("readCapacity must be greater than 5 or less than 20"); } } ... } } {{}} Now lets add a test that validates the error is thrown. ```java @Test public void testDynamoDBRaises() throws IOException { Stack stack = new Stack(); Function hello = Function.Builder.create(stack, "HelloHandler") .runtime(Runtime.NODEJS_14_X) .code(Code.fromAsset("lambda")) .handler("hello.handler") .build(); assertThrows(RuntimeException.class, () -> { new HitCounter(stack, "HelloHitCounter", HitCounterProps.builder() .downstream(hello) .readCapacity(1) .build()); }); } ``` Run the test. ```bash $ mvn test ``` You should see an output like this: ```bash $ mvn test ------------------------------------------------------- T E S T S ------------------------------------------------------- Running com.myorg.HitCounterTest Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.828 sec Results : Tests run: 4, Failures: 0, Errors: 0, Skipped: 0 [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 10.148 s [INFO] Finished at: 2021-11-01T12:54:45Z [INFO] ------------------------------------------------------------------------ ```