diff --git a/spring-boot-samples/pom.xml b/spring-boot-samples/pom.xml index 3fb2f76fa2..4ad586d157 100644 --- a/spring-boot-samples/pom.xml +++ b/spring-boot-samples/pom.xml @@ -76,6 +76,7 @@ spring-boot-sample-servlet spring-boot-sample-session-redis spring-boot-sample-simple + spring-boot-sample-test spring-boot-sample-testng spring-boot-sample-tomcat spring-boot-sample-tomcat-jsp diff --git a/spring-boot-samples/spring-boot-sample-test/pom.xml b/spring-boot-samples/spring-boot-sample-test/pom.xml new file mode 100644 index 0000000000..e54c05f06b --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/pom.xml @@ -0,0 +1,62 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-samples + 1.4.0.BUILD-SNAPSHOT + + spring-boot-sample-test + Spring Boot Test Sample + Spring Boot Test Sample + http://projects.spring.io/spring-boot/ + + Pivotal Software, Inc. + http://www.spring.io + + + ${basedir}/../.. + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + + + mysql + mysql-connector-java + + + org.springframework.boot + spring-boot-starter-test + test + + + org.seleniumhq.selenium + selenium-htmlunit-driver + test + + + net.sourceforge.htmlunit + htmlunit + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/SampleTestApplication.java b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/SampleTestApplication.java new file mode 100644 index 0000000000..782c35b92a --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/SampleTestApplication.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * Sample application to demonstrate testing. + * + * @author Phillip Webb + */ +@SpringBootApplication +public class SampleTestApplication { + + // NOTE: this application will intentionally not start without MySQL, the test will + // still run. + + public static void main(String[] args) { + SpringApplication.run(SampleTestApplication.class, args); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/WelcomeCommandLineRunner.java b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/WelcomeCommandLineRunner.java new file mode 100644 index 0000000000..5f677a3f44 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/WelcomeCommandLineRunner.java @@ -0,0 +1,36 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test; + +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +/** + * Simple component that just prints a message. Used to show how different types of + * integration tests work. + * + * @author Phillip Webb + */ +@Component +public class WelcomeCommandLineRunner implements CommandLineRunner { + + @Override + public void run(String... args) throws Exception { + System.out.println("***** WELCOME TO THE DEMO *****"); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/domain/User.java b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/domain/User.java new file mode 100644 index 0000000000..51549f65cd --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/domain/User.java @@ -0,0 +1,65 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.domain; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +import org.springframework.util.Assert; + +/** + * A user of the system. + * + * @author Phillip Webb + */ +@Entity +public class User { + + @Id + @GeneratedValue + private Long id; + + @Column(unique = true) + private String username; + + private VehicleIdentificationNumber vin; + + protected User() { + } + + public User(String username, VehicleIdentificationNumber vin) { + Assert.hasLength(username, "Username must not be empty"); + Assert.notNull(vin, "VIN must not be null"); + this.username = username; + this.vin = vin; + } + + protected Long getId() { + return this.id; + } + + public String getUsername() { + return this.username; + } + + public VehicleIdentificationNumber getVin() { + return this.vin; + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/domain/UserRepository.java b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/domain/UserRepository.java new file mode 100644 index 0000000000..12d1e559d4 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/domain/UserRepository.java @@ -0,0 +1,30 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.domain; + +import org.springframework.data.repository.Repository; + +/** + * Domain repository for {@link User} + * + * @author Phillip Webb + */ +public interface UserRepository extends Repository { + + User findByUsername(String username); + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/domain/VehicleIdentificationNumber.java b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/domain/VehicleIdentificationNumber.java new file mode 100644 index 0000000000..c3ac249fe8 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/domain/VehicleIdentificationNumber.java @@ -0,0 +1,57 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.domain; + +import org.springframework.util.Assert; + +/** + * A Vehicle Identification Number. + * + * @author Phillip Webb + */ +public final class VehicleIdentificationNumber { + + private String vin; + + public VehicleIdentificationNumber(String vin) { + Assert.notNull(vin, "VIN must not be null"); + Assert.isTrue(vin.length() == 17, "VIN must be exactly 17 characters"); + this.vin = vin; + } + + @Override + public int hashCode() { + return this.vin.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj == null || obj.getClass() != getClass()) { + return false; + } + return this.vin.equals(((VehicleIdentificationNumber) obj).vin); + } + + @Override + public String toString() { + return this.vin; + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/domain/VehicleIdentificationNumberAttributeConverter.java b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/domain/VehicleIdentificationNumberAttributeConverter.java new file mode 100644 index 0000000000..3cdf0515b5 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/domain/VehicleIdentificationNumberAttributeConverter.java @@ -0,0 +1,41 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.domain; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; + +/** + * JPA {@link AttributeConverter} for {@link VehicleIdentificationNumber}. + * + * @author Phillip Webb + */ +@Converter(autoApply = true) +public class VehicleIdentificationNumberAttributeConverter + implements AttributeConverter { + + @Override + public String convertToDatabaseColumn(VehicleIdentificationNumber attribute) { + return attribute.toString(); + } + + @Override + public VehicleIdentificationNumber convertToEntityAttribute(String dbData) { + return new VehicleIdentificationNumber(dbData); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/service/RemoteVehicleDetailsService.java b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/service/RemoteVehicleDetailsService.java new file mode 100644 index 0000000000..0a99173501 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/service/RemoteVehicleDetailsService.java @@ -0,0 +1,70 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.service; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sample.test.domain.VehicleIdentificationNumber; + +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.util.Assert; +import org.springframework.web.client.HttpStatusCodeException; +import org.springframework.web.client.RestTemplate; + +/** + * {@link VehicleDetailsService} backed by a remote REST service. + * + * @author Phillip Webb + */ +@Service +public class RemoteVehicleDetailsService implements VehicleDetailsService { + + private static final Logger logger = LoggerFactory + .getLogger(RemoteVehicleDetailsService.class); + + private final ServiceProperties properties; + + private final RestTemplate restTemplate; + + public RemoteVehicleDetailsService(ServiceProperties properties) { + this.properties = properties; + this.restTemplate = new RestTemplate(); + } + + protected final RestTemplate getRestTemplate() { + return this.restTemplate; + } + + @Override + public VehicleDetails getVehicleDetails(VehicleIdentificationNumber vin) + throws VehicleIdentificationNumberNotFoundException { + Assert.notNull(vin, "VIN must not be null"); + String url = this.properties.getVehicleServiceRootUrl() + "vehicle/{vin}/details"; + logger.debug("Retrieving vehicle data for: " + vin + " from: " + url); + try { + return this.restTemplate.getForObject(url, VehicleDetails.class, vin); + } + catch (HttpStatusCodeException ex) { + if (HttpStatus.NOT_FOUND.equals(ex.getStatusCode())) { + throw new VehicleIdentificationNumberNotFoundException(vin, ex); + } + throw ex; + } + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/service/ServiceProperties.java b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/service/ServiceProperties.java new file mode 100644 index 0000000000..9222fbd46f --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/service/ServiceProperties.java @@ -0,0 +1,41 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.service; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * Properties for the service. + * + * @author Phillip Webb + */ +@Component +@ConfigurationProperties +public class ServiceProperties { + + private String vehicleServiceRootUrl = "http://localhost:8080/vs/"; + + public String getVehicleServiceRootUrl() { + return this.vehicleServiceRootUrl; + } + + public void setVehicleServiceRootUrl(String vehicleServiceRootUrl) { + this.vehicleServiceRootUrl = vehicleServiceRootUrl; + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/service/VehicleDetails.java b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/service/VehicleDetails.java new file mode 100644 index 0000000000..e0515ff56d --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/service/VehicleDetails.java @@ -0,0 +1,69 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.service; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import org.springframework.util.Assert; + +/** + * Details of a single vehicle. + * + * @author Phillip Webb + */ +public class VehicleDetails { + + private final String make; + + private final String model; + + @JsonCreator + public VehicleDetails(@JsonProperty("make") String make, + @JsonProperty("model") String model) { + Assert.notNull(make, "Make must not be null"); + Assert.notNull(model, "Model must not be null"); + this.make = make; + this.model = model; + } + + public String getMake() { + return this.make; + } + + public String getModel() { + return this.model; + } + + @Override + public int hashCode() { + return this.make.hashCode() * 31 + this.model.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj == null || obj.getClass() != getClass()) { + return false; + } + VehicleDetails other = (VehicleDetails) obj; + return this.make.equals(other.make) && this.model.equals(other.model); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/service/VehicleDetailsService.java b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/service/VehicleDetailsService.java new file mode 100644 index 0000000000..326b1fb85b --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/service/VehicleDetailsService.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.service; + +import sample.test.domain.VehicleIdentificationNumber; + +/** + * A service to obtain {@link VehicleDetails} given a {@link VehicleIdentificationNumber}. + * + * @author Phillip Webb + */ +public interface VehicleDetailsService { + + /** + * Get vehicle details for a given {@link VehicleIdentificationNumber}. + * @param vin the vehicle identification number + * @return vehicle details + * @throws VehicleIdentificationNumberNotFoundException if the VIN is not known + */ + VehicleDetails getVehicleDetails(VehicleIdentificationNumber vin) + throws VehicleIdentificationNumberNotFoundException; + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/service/VehicleIdentificationNumberNotFoundException.java b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/service/VehicleIdentificationNumberNotFoundException.java new file mode 100644 index 0000000000..cfa7b59047 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/service/VehicleIdentificationNumberNotFoundException.java @@ -0,0 +1,43 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.service; + +import sample.test.domain.VehicleIdentificationNumber; + +/** + * Exception thrown when a {@link VehicleIdentificationNumber} is not found. + * + * @author Phillip Webb + */ +public class VehicleIdentificationNumberNotFoundException extends RuntimeException { + + private VehicleIdentificationNumber vehicleIdentificationNumber; + + public VehicleIdentificationNumberNotFoundException(VehicleIdentificationNumber vin) { + this(vin, null); + } + + public VehicleIdentificationNumberNotFoundException(VehicleIdentificationNumber vin, + Throwable cause) { + super("Unable to find VehicleIdentificationNumber " + vin, cause); + this.vehicleIdentificationNumber = vin; + } + + public VehicleIdentificationNumber getVehicleIdentificationNumber() { + return this.vehicleIdentificationNumber; + } +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/web/UserNameNotFoundException.java b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/web/UserNameNotFoundException.java new file mode 100644 index 0000000000..4c4a1e680b --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/web/UserNameNotFoundException.java @@ -0,0 +1,35 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.web; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(HttpStatus.NOT_FOUND) +public class UserNameNotFoundException extends RuntimeException { + + private String username; + + public UserNameNotFoundException(String username) { + this.username = username; + } + + public String getUsername() { + return this.username; + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/web/UserVehicleController.java b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/web/UserVehicleController.java new file mode 100644 index 0000000000..9085ec6b6d --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/web/UserVehicleController.java @@ -0,0 +1,68 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.web; + +import sample.test.domain.User; +import sample.test.service.VehicleDetails; +import sample.test.service.VehicleIdentificationNumberNotFoundException; + +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +/** + * Controller to return vehicle information for a given {@link User} + * + * @author Phillip Webb + */ +@RestController +public class UserVehicleController { + + private UserVehicleService userVehicleService; + + public UserVehicleController(UserVehicleService userVehicleService) { + this.userVehicleService = userVehicleService; + } + + @GetMapping(path = "/{username}/vehicle", produces = MediaType.TEXT_PLAIN_VALUE) + public String getVehicleDetailsText(@PathVariable String username) { + VehicleDetails details = this.userVehicleService.getVehicleDetails(username); + return details.getMake() + " " + details.getModel(); + } + + @GetMapping(path = "/{username}/vehicle", produces = MediaType.APPLICATION_JSON_VALUE) + public VehicleDetails VehicleDetailsJson(@PathVariable String username) { + return this.userVehicleService.getVehicleDetails(username); + } + + @GetMapping(path = "/{username}/vehicle.html", produces = MediaType.TEXT_HTML_VALUE) + public String VehicleDetailsHtml(@PathVariable String username) { + VehicleDetails details = this.userVehicleService.getVehicleDetails(username); + String makeAndModel = details.getMake() + " " + details.getModel(); + return "

" + makeAndModel + "

"; + } + + @ExceptionHandler + @ResponseStatus(HttpStatus.NOT_FOUND) + private void handleVinNotFound(VehicleIdentificationNumberNotFoundException ex) { + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/web/UserVehicleService.java b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/web/UserVehicleService.java new file mode 100644 index 0000000000..1ac6443f0a --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/main/java/sample/test/web/UserVehicleService.java @@ -0,0 +1,57 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.web; + +import sample.test.domain.User; +import sample.test.domain.UserRepository; +import sample.test.service.VehicleDetails; +import sample.test.service.VehicleDetailsService; +import sample.test.service.VehicleIdentificationNumberNotFoundException; + +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; + +/** + * Controller service used to provide vehicle information for a given user. + * + * @author Phillip Webb + */ +@Component +public class UserVehicleService { + + private final UserRepository userRepository; + + private final VehicleDetailsService vehicleDetailsService; + + public UserVehicleService(UserRepository userRepository, + VehicleDetailsService vehicleDetailsService) { + this.userRepository = userRepository; + this.vehicleDetailsService = vehicleDetailsService; + } + + public VehicleDetails getVehicleDetails(String username) + throws UserNameNotFoundException, + VehicleIdentificationNumberNotFoundException { + Assert.notNull(username, "Username must not be null"); + User user = this.userRepository.findByUsername(username); + if (user == null) { + throw new UserNameNotFoundException(username); + } + return this.vehicleDetailsService.getVehicleDetails(user.getVin()); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-test/src/main/resources/application.properties new file mode 100644 index 0000000000..c28dbb20bc --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.datasource.url=jdbc:mysql://localhost/doesnotexist diff --git a/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/SampleTestApplicationWebIntegrationTests.java b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/SampleTestApplicationWebIntegrationTests.java new file mode 100644 index 0000000000..94801f81c4 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/SampleTestApplicationWebIntegrationTests.java @@ -0,0 +1,65 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import sample.test.domain.VehicleIdentificationNumber; +import sample.test.service.VehicleDetails; +import sample.test.service.VehicleDetailsService; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.web.WebIntegrationTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.mockito.BDDMockito.given; + +/** + * {@code @WebIntegrationTest} for {@link SampleTestApplication}. + * + * @author Phillip Webb + */ +@RunWith(SpringRunner.class) +@WebIntegrationTest(randomPort = true) +@AutoConfigureTestDatabase +public class SampleTestApplicationWebIntegrationTests { + + private static final VehicleIdentificationNumber VIN = new VehicleIdentificationNumber( + "01234567890123456"); + + @Autowired + private TestRestTemplate restTemplate; + + @MockBean + private VehicleDetailsService vehicleDetailsService; + + @Before + public void setup() { + given(this.vehicleDetailsService.getVehicleDetails(VIN)) + .willReturn(new VehicleDetails("Honda", "Civic")); + } + + @Test + public void test() { + this.restTemplate.getForEntity("/{username}/vehicle", String.class, "sframework"); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/domain/UserEntityTests.java b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/domain/UserEntityTests.java new file mode 100644 index 0000000000..afa48727c9 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/domain/UserEntityTests.java @@ -0,0 +1,77 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.domain; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Data JPA tests for {@link User}. + * + * @author Phillip Webb + */ +@RunWith(SpringRunner.class) +@DataJpaTest +public class UserEntityTests { + + private static final VehicleIdentificationNumber VIN = new VehicleIdentificationNumber( + "00000000000000000"); + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Autowired + private TestEntityManager entityManager; + + @Test + public void createWhenUserIdIsNullShouldThrowException() throws Exception { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Username must not be empty"); + new User(null, VIN); + } + + @Test + public void createWhenUserIdIsEmptyShouldThrowException() throws Exception { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Username must not be empty"); + new User("", VIN); + } + + @Test + public void createWhenVinIsNullShouldThrowException() throws Exception { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("VIN must not be null"); + new User("sboot", null); + } + + @Test + public void saveShouldPersistData() throws Exception { + User user = this.entityManager.persistFlushFind(new User("sboot", VIN)); + assertThat(user.getUsername()).isEqualTo("sboot"); + assertThat(user.getVin()).isEqualTo(VIN); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/domain/UserRepositoryTests.java b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/domain/UserRepositoryTests.java new file mode 100644 index 0000000000..b61f2d0bbc --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/domain/UserRepositoryTests.java @@ -0,0 +1,62 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.domain; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link UserRepository}. + * + * @author Phillip Webb + */ +@RunWith(SpringRunner.class) +@DataJpaTest +public class UserRepositoryTests { + + private static final VehicleIdentificationNumber VIN = new VehicleIdentificationNumber( + "00000000000000000"); + + @Autowired + private TestEntityManager entityManager; + + @Autowired + private UserRepository repository; + + @Test + public void findByUsernameShouldReturnUser() throws Exception { + this.entityManager.persist(new User("sboot", VIN)); + User user = this.repository.findByUsername("sboot"); + assertThat(user.getUsername()).isEqualTo("sboot"); + assertThat(user.getVin()).isEqualTo(VIN); + } + + @Test + public void findByUsernameWhenNoUserShouldReturnNull() throws Exception { + this.entityManager.persist(new User("sboot", VIN)); + User user = this.repository.findByUsername("mmouse"); + assertThat(user).isNull(); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/domain/VehicleIdentificationNumberTests.java b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/domain/VehicleIdentificationNumberTests.java new file mode 100644 index 0000000000..ede0046ee5 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/domain/VehicleIdentificationNumberTests.java @@ -0,0 +1,77 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.domain; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link VehicleIdentificationNumber}. + * + * @author Phillip Webb + * @see + * Naming standards for unit tests + * @see AssertJ + */ +public class VehicleIdentificationNumberTests { + + private static final String SAMPLE_VIN = "41549485710496749"; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void createWhenVinIsNullShouldThrowException() throws Exception { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("VIN must not be null"); + new VehicleIdentificationNumber(null); + } + + @Test + public void createWhenVinIsMoreThan17CharsShouldThrowException() throws Exception { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("VIN must be exactly 17 characters"); + new VehicleIdentificationNumber("012345678901234567"); + } + + @Test + public void createWhenVinIsLessThan17CharsShouldThrowException() throws Exception { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("VIN must be exactly 17 characters"); + new VehicleIdentificationNumber("0123456789012345"); + } + + @Test + public void toStringShouldReturnVin() throws Exception { + VehicleIdentificationNumber vin = new VehicleIdentificationNumber(SAMPLE_VIN); + assertThat(vin.toString()).isEqualTo(SAMPLE_VIN); + } + + @Test + public void equalsAndHashShouldBeBasedOnVin() throws Exception { + VehicleIdentificationNumber vin1 = new VehicleIdentificationNumber(SAMPLE_VIN); + VehicleIdentificationNumber vin2 = new VehicleIdentificationNumber(SAMPLE_VIN); + VehicleIdentificationNumber vin3 = new VehicleIdentificationNumber( + "00000000000000000"); + assertThat(vin1.hashCode()).isEqualTo(vin2.hashCode()); + assertThat(vin1).isEqualTo(vin1).isEqualTo(vin2).isNotEqualTo(vin3); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/service/RemoteVehicleDetailsServiceTests.java b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/service/RemoteVehicleDetailsServiceTests.java new file mode 100644 index 0000000000..4216f56b00 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/service/RemoteVehicleDetailsServiceTests.java @@ -0,0 +1,102 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.service; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import sample.test.domain.VehicleIdentificationNumber; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.web.client.HttpServerErrorException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withServerError; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; + +/** + * Tests for {@link RemoteVehicleDetailsService}. + * + * @author Phillip Webb + */ +public class RemoteVehicleDetailsServiceTests { + + private static final String VIN = "00000000000000000"; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private RemoteVehicleDetailsService service; + + private MockRestServiceServer server; + + @Before + public void setup() { + ServiceProperties properties = new ServiceProperties(); + properties.setVehicleServiceRootUrl("http://example.com/"); + this.service = new RemoteVehicleDetailsService(properties); + this.server = MockRestServiceServer.createServer(this.service.getRestTemplate()); + } + + @Test + public void getVehicleDetailsWhenVinIsNullShouldThrowException() throws Exception { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("VIN must not be null"); + this.service.getVehicleDetails(null); + } + + @Test + public void getVehicleDetailsWhenResultIsSuccessShouldReturnDetails() + throws Exception { + this.server.expect(requestTo("http://example.com/vehicle/" + VIN + "/details")) + .andRespond(withSuccess(getClassPathResource("vehicledetails.json"), + MediaType.APPLICATION_JSON)); + VehicleDetails details = this.service + .getVehicleDetails(new VehicleIdentificationNumber(VIN)); + assertThat(details.getMake()).isEqualTo("Honda"); + assertThat(details.getModel()).isEqualTo("Civic"); + } + + @Test + public void getVehicleDetailsWhenResultIsNotFoundShouldThrowException() + throws Exception { + this.server.expect(requestTo("http://example.com/vehicle/" + VIN + "/details")) + .andRespond(withStatus(HttpStatus.NOT_FOUND)); + this.thrown.expect(VehicleIdentificationNumberNotFoundException.class); + this.service.getVehicleDetails(new VehicleIdentificationNumber(VIN)); + } + + @Test + public void getVehicleDetailsWhenResultIServerErrorShouldThrowException() + throws Exception { + this.server.expect(requestTo("http://example.com/vehicle/" + VIN + "/details")) + .andRespond(withServerError()); + this.thrown.expect(HttpServerErrorException.class); + this.service.getVehicleDetails(new VehicleIdentificationNumber(VIN)); + } + + private ClassPathResource getClassPathResource(String path) { + return new ClassPathResource(path, getClass()); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/service/VehicleDetailsJsonTests.java b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/service/VehicleDetailsJsonTests.java new file mode 100644 index 0000000000..89848ff487 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/service/VehicleDetailsJsonTests.java @@ -0,0 +1,57 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.service; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.json.JacksonTester; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * JSON Tests for {@link VehicleDetails}. + * + * @author Phillip Webb + */ +@RunWith(SpringRunner.class) +@JsonTest +public class VehicleDetailsJsonTests { + + private JacksonTester json; + + @Test + public void serializeJson() throws Exception { + VehicleDetails details = new VehicleDetails("Honda", "Civic"); + assertThat(this.json.write(details)).isEqualTo("vehicledetails.json"); + assertThat(this.json.write(details)).isEqualToJson("vehicledetails.json"); + assertThat(this.json.write(details)).hasJsonPathStringValue("@.make"); + assertThat(this.json.write(details)).extractingJsonPathStringValue("@.make") + .isEqualTo("Honda"); + } + + @Test + public void deserializeJson() throws Exception { + String content = "{\"make\":\"Ford\",\"model\":\"Focus\"}"; + assertThat(this.json.parse(content)) + .isEqualTo(new VehicleDetails("Ford", "Focus")); + assertThat(this.json.parseObject(content).getMake()).isEqualTo("Ford"); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/web/UserVehicleControllerApplicationTests.java b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/web/UserVehicleControllerApplicationTests.java new file mode 100644 index 0000000000..12732c802b --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/web/UserVehicleControllerApplicationTests.java @@ -0,0 +1,75 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.web; + +import org.junit.Test; +import org.junit.runner.RunWith; +import sample.test.WelcomeCommandLineRunner; +import sample.test.service.VehicleDetails; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringApplicationTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.ApplicationContext; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * {@code @SpringApplicationTest} based tests for {@link UserVehicleController}. + * + * @author Phillip Webb + */ +@RunWith(SpringRunner.class) +@SpringApplicationTest +@AutoConfigureMockMvc +@AutoConfigureTestDatabase +public class UserVehicleControllerApplicationTests { + + @Autowired + private MockMvc mvc; + + @Autowired + private ApplicationContext applicationContext; + + @MockBean + private UserVehicleService userVehicleService; + + @Test + public void getVehicleWhenRequestingTextShouldReturnMakeAndModel() throws Exception { + given(this.userVehicleService.getVehicleDetails("sboot")) + .willReturn(new VehicleDetails("Honda", "Civic")); + this.mvc.perform(get("/sboot/vehicle").accept(MediaType.TEXT_PLAIN)) + .andExpect(status().isOk()).andExpect(content().string("Honda Civic")); + } + + @Test + public void welcomeCommandLineRunnerShouldBeAvailble() throws Exception { + // Since we're a @SpringApplicationTest all beans should be available + assertThat(this.applicationContext.getBean(WelcomeCommandLineRunner.class)) + .isNotNull(); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/web/UserVehicleControllerHtmlUnitTests.java b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/web/UserVehicleControllerHtmlUnitTests.java new file mode 100644 index 0000000000..2aee09405e --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/web/UserVehicleControllerHtmlUnitTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.web; + +import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.html.HtmlPage; +import org.junit.Test; +import org.junit.runner.RunWith; +import sample.test.service.VehicleDetails; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; + +/** + * HtmlUnit based tests for {@link UserVehicleController}. + * + * @author Phillip Webb + */ +@RunWith(SpringRunner.class) +@WebMvcTest(UserVehicleController.class) +public class UserVehicleControllerHtmlUnitTests { + + @Autowired + private WebClient webClient; + + @MockBean + private UserVehicleService userVehicleService; + + @Test + public void getVehicleWhenRequestingTextShouldReturnMakeAndModel() throws Exception { + given(this.userVehicleService.getVehicleDetails("sboot")) + .willReturn(new VehicleDetails("Honda", "Civic")); + HtmlPage page = this.webClient.getPage("/sboot/vehicle.html"); + assertThat(page.getBody().getTextContent()).isEqualTo("Honda Civic"); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/web/UserVehicleControllerSeleniumTests.java b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/web/UserVehicleControllerSeleniumTests.java new file mode 100644 index 0000000000..ca54240f75 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/web/UserVehicleControllerSeleniumTests.java @@ -0,0 +1,58 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.web; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import sample.test.service.VehicleDetails; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; + +/** + * Selenium based tests for {@link UserVehicleController}. + * + * @author Phillip Webb + */ +@RunWith(SpringRunner.class) +@WebMvcTest(UserVehicleController.class) +public class UserVehicleControllerSeleniumTests { + + @Autowired + private WebDriver webDriver; + + @MockBean + private UserVehicleService userVehicleService; + + @Test + public void getVehicleWhenRequestingTextShouldReturnMakeAndModel() throws Exception { + given(this.userVehicleService.getVehicleDetails("sboot")) + .willReturn(new VehicleDetails("Honda", "Civic")); + this.webDriver.get("/sboot/vehicle.html"); + WebElement element = this.webDriver.findElement(By.tagName("h1")); + assertThat(element.getText()).isEqualTo("Honda Civic"); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/web/UserVehicleControllerTests.java b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/web/UserVehicleControllerTests.java new file mode 100644 index 0000000000..8a4575053a --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/web/UserVehicleControllerTests.java @@ -0,0 +1,109 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.web; + +import org.junit.Test; +import org.junit.runner.RunWith; +import sample.test.WelcomeCommandLineRunner; +import sample.test.domain.VehicleIdentificationNumber; +import sample.test.service.VehicleDetails; +import sample.test.service.VehicleIdentificationNumberNotFoundException; + +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.ApplicationContext; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * {@code @WebMvcTest} based tests for {@link UserVehicleController}. + * + * @author Phillip Webb + */ +@RunWith(SpringRunner.class) +@WebMvcTest(UserVehicleController.class) +public class UserVehicleControllerTests { + + private static final VehicleIdentificationNumber VIN = new VehicleIdentificationNumber( + "00000000000000000"); + + @Autowired + private MockMvc mvc; + + @Autowired + private ApplicationContext applicationContext; + + @MockBean + private UserVehicleService userVehicleService; + + @Test + public void getVehicleWhenRequestingTextShouldReturnMakeAndModel() throws Exception { + given(this.userVehicleService.getVehicleDetails("sboot")) + .willReturn(new VehicleDetails("Honda", "Civic")); + this.mvc.perform(get("/sboot/vehicle").accept(MediaType.TEXT_PLAIN)) + .andExpect(status().isOk()).andExpect(content().string("Honda Civic")); + } + + @Test + public void getVehicleWhenRequestingJsonShouldReturnMakeAndModel() throws Exception { + given(this.userVehicleService.getVehicleDetails("sboot")) + .willReturn(new VehicleDetails("Honda", "Civic")); + this.mvc.perform(get("/sboot/vehicle").accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().json("{'make':'Honda','model':'Civic'}")); + } + + @Test + public void getVehicleWhenRequestingHtmlShouldReturnMakeAndModel() throws Exception { + given(this.userVehicleService.getVehicleDetails("sboot")) + .willReturn(new VehicleDetails("Honda", "Civic")); + this.mvc.perform(get("/sboot/vehicle.html").accept(MediaType.TEXT_HTML)) + .andExpect(status().isOk()) + .andExpect(content().string(containsString("

Honda Civic

"))); + } + + @Test + public void getVehicleWhenUserNotFoundShouldReturnNotFound() throws Exception { + given(this.userVehicleService.getVehicleDetails("sboot")) + .willThrow(new UserNameNotFoundException("sboot")); + this.mvc.perform(get("/sboot/vehicle")).andExpect(status().isNotFound()); + } + + @Test + public void getVehicleWhenVinNotFoundShouldReturnNotFound() throws Exception { + given(this.userVehicleService.getVehicleDetails("sboot")) + .willThrow(new VehicleIdentificationNumberNotFoundException(VIN)); + this.mvc.perform(get("/sboot/vehicle")).andExpect(status().isNotFound()); + } + + @Test(expected = NoSuchBeanDefinitionException.class) + public void welcomeCommandLineRunnerShouldBeAvailble() throws Exception { + // Since we're a @WebMvcTest WelcomeCommandLineRunner should not be available + assertThat(this.applicationContext.getBean(WelcomeCommandLineRunner.class)); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/web/UserVehicleServiceTests.java b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/web/UserVehicleServiceTests.java new file mode 100644 index 0000000000..ce32fdc1a7 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/test/java/sample/test/web/UserVehicleServiceTests.java @@ -0,0 +1,89 @@ +/* + * Copyright 2012-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sample.test.web; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import sample.test.domain.User; +import sample.test.domain.UserRepository; +import sample.test.domain.VehicleIdentificationNumber; +import sample.test.service.VehicleDetails; +import sample.test.service.VehicleDetailsService; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Matchers.anyString; + +/** + * Tests for {@link UserVehicleService}. + * + * @author Phillip Webb + */ +public class UserVehicleServiceTests { + + private static final VehicleIdentificationNumber VIN = new VehicleIdentificationNumber( + "00000000000000000"); + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Mock + private VehicleDetailsService vehicleDetailsService; + + @Mock + private UserRepository userRepository; + + private UserVehicleService service; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + this.service = new UserVehicleService(this.userRepository, + this.vehicleDetailsService); + } + + @Test + public void getVehicleDetailsWhenUsernameIsNullShouldThrowException() + throws Exception { + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Username must not be null"); + this.service.getVehicleDetails(null); + } + + @Test + public void getVehicleDetailsWhenUserNameNotFoundShouldThrowException() + throws Exception { + given(this.userRepository.findByUsername(anyString())).willReturn(null); + this.thrown.expect(UserNameNotFoundException.class); + this.service.getVehicleDetails("sboot"); + } + + @Test + public void getVehicleDetailsShouldReturnMakeAndModel() throws Exception { + given(this.userRepository.findByUsername(anyString())) + .willReturn(new User("sboot", VIN)); + VehicleDetails details = new VehicleDetails("Honda", "Civic"); + given(this.vehicleDetailsService.getVehicleDetails(VIN)).willReturn(details); + VehicleDetails actual = this.service.getVehicleDetails("sboot"); + assertThat(actual).isEqualTo(details); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-test/src/test/resources/data.sql b/spring-boot-samples/spring-boot-sample-test/src/test/resources/data.sql new file mode 100644 index 0000000000..70ecc99a37 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/test/resources/data.sql @@ -0,0 +1 @@ +INSERT INTO USER(ID, USERNAME, VIN) values (123, 'sframework', '01234567890123456'); diff --git a/spring-boot-samples/spring-boot-sample-test/src/test/resources/sample/test/service/vehicledetails.json b/spring-boot-samples/spring-boot-sample-test/src/test/resources/sample/test/service/vehicledetails.json new file mode 100644 index 0000000000..b0a453d566 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-test/src/test/resources/sample/test/service/vehicledetails.json @@ -0,0 +1,4 @@ +{ + "make" : "Honda", + "model" : "Civic" +}