spring-boot
Testning i Spring Boot
Sök…
Hur man testar en enkel Spring Boot-applikation
Vi har ett exempel på vårstartprogram som lagrar användardata i MongoDB och vi använder Resttjänster för att hämta data
Först finns det en domänklass, dvs. POJO
@Document
public class User{
@Id
private String id;
private String name;
}
Ett motsvarande arkiv baserat på Spring Data MongoDB
public interface UserRepository extends MongoRepository<User, String> {
}
Sedan vår användarkontroller
@RestController
class UserController {
@Autowired
private UserRepository repository;
@RequestMapping("/users")
List<User> users() {
return repository.findAll();
}
@RequestMapping(value = "/Users/{id}", method = RequestMethod.DELETE)
@ResponseStatus(HttpStatus.NO_CONTENT)
void delete(@PathVariable("id") String id) {
repository.delete(id);
}
// more controller methods
}
Och slutligen vår Spring Boot Application
@SpringBootApplication
public class Application {
public static void main(String args[]){
SpringApplication.run(Application.class, args);
}
}
Om, låt oss säga att John Cena, The Rock och TripleHHH var de enda tre användarna i databasen, skulle en begäran till / användare ge följande svar:
$ curl localhost:8080/users
[{"name":"John Cena","id":"1"},{"name":"The Rock","id":"2"},{"name":"TripleHHH","id":"3"}]
För att testa koden kommer vi nu att verifiera att applikationen fungerar
@RunWith(SpringJUnit4ClassRunner.class) // 1
@SpringApplicationConfiguration(classes = Application.class) // 2
@WebAppConfiguration // 3
@IntegrationTest("server.port:0") // 4
public class UserControllerTest {
@Autowired // 5
UserRepository repository;
User cena;
User rock;
User tripleHHH;
@Value("${local.server.port}") // 6
int port;
@Before
public void setUp() {
// 7
cena = new User("John Cena");
rock = new User("The Rock");
tripleHHH = new User("TripleHH");
// 8
repository.deleteAll();
repository.save(Arrays.asList(cena, rock, tripleHHH));
// 9
RestAssured.port = port;
}
// 10
@Test
public void testFetchCena() {
String cenaId = cena.getId();
when().
get("/Users/{id}", cenaId).
then().
statusCode(HttpStatus.SC_OK).
body("name", Matchers.is("John Cena")).
body("id", Matchers.is(cenaId));
}
@Test
public void testFetchAll() {
when().
get("/users").
then().
statusCode(HttpStatus.SC_OK).
body("name", Matchers.hasItems("John Cena", "The Rock", "TripleHHH"));
}
@Test
public void testDeletetripleHHH() {
String tripleHHHId = tripleHHH.getId();
when()
.delete("/Users/{id}", tripleHHHId).
then().
statusCode(HttpStatus.SC_NO_CONTENT);
}
}
Förklaring
- Liksom alla andra
SpringJUnit4ClassRunner
behöver viSpringJUnit4ClassRunner
så att en applikationskontekst skapas. -
@SpringApplicationConfiguration
kommentarerna liknar@ContextConfiguration
kommentaren genom att den används för att ange vilka applikationskontext (er) som ska användas i testet. Dessutom kommer den att utlösa logik för att läsa Spring Boot-specifika konfigurationer, egenskaper och så vidare. -
@WebAppConfiguration
måste finnas för att berätta för våren att enWebApplicationContext
bör laddas för testet. Det ger också ett attribut för att ange sökvägen till roten till webbapplikationen. -
@IntegrationTest
används för att berätta för Spring Boot att den inbäddade webbservern bör startas. Genom att tillhandahålla kolonn- eller lika-separerade namnvärdespar kan alla miljövariabler åsidosättas. I det här exemplet"server.port:0"
serverns standardportinställning. Normalt börjar servern använda det angivna portnumret, men värdet 0 har en speciell betydelse. När det anges som 0, berättar det för Spring Boot att skanna portarna i värdmiljön och starta servern på en slumpmässig, tillgänglig port. Det är användbart om vi har olika tjänster som upptar olika portar på utvecklingsmaskinerna och build-servern som potentiellt kan kollidera med applikationsporten, i vilket fall applikationen inte kommer att starta. För det andra, om vi skapar flera integrationstester med olika applikationskontekster, kan de också kollidera om testerna körs samtidigt. - Vi har tillgång till applikationens sammanhang och kan använda autowiring för att injicera vilken som helst vårböna.
-
@Value("${local.server.port}”)
kommer att lösas till det faktiska portnumret som används. - Vi skapar några enheter som vi kan använda för validering.
- MongoDB-databasen rensas och initialiseras på nytt för varje test så att vi alltid validerar mot ett känt tillstånd. Eftersom testens ordning inte är definierad är chansen stor att testet TestFetchAll () misslyckas om det utförs efter testetDeletetripleHHH () -testet.
- Vi instruerar Rest Assured att använda rätt port. Det är ett öppen källkodsprojekt som tillhandahåller en Java DSL för att testa vilsamma tjänster
- Test genomförs med hjälp av Rest Assured. vi kan implementera testerna med TestRestTemplate eller någon annan http-klient, men jag använder Rest Assured eftersom vi kan skriva kortfattad dokumentation med RestDocs
Laddar annan yaml [eller egenskaper] -fil eller åsidosätter vissa egenskaper
När vi använder @SpringApplicationConfiguration
kommer den att använda konfigurering från application.yml
[egenskaper] som i vissa situationer inte är lämpligt. Så för att åsidosätta egenskaperna kan vi använda @TestPropertySource
kommentarer.
@TestPropertySource(
properties = {
"spring.jpa.hibernate.ddl-auto=create-drop",
"liquibase.enabled=false"
}
)
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class ApplicationTest{
// ...
}
Vi kan använda egenskaper attribut för @TestPropertySource
att åsidosätta de specifika egenskaper vi vill ha. I exemplet ovan åsidosätter vi egenskapen spring.jpa.hibernate.ddl-auto
att create-drop
. Och liquibase.enabled
till false
.
Laddar olika yml-filer
Om du vill helt ladda olika YML fil för test kan du använda platser attribut på @TestPropertySource
.
@TestPropertySource(locations="classpath:test.yml")
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(Application.class)
public class ApplicationTest{
// ...
}
Alternativt alternativ
Alternativ 1:
Du kan också ladda olika yml- filer när jag placerar en yml- fil på test > resource
Alternativ 2:
Använda @ActiveProfiles
kommentarer
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@ActiveProfiles("somename")
public class MyIntTest{
}
Du kan se att vi använder @ActiveProfiles
kommentarer och vi skickar namnet som värdet.
Skapa en fil som heter application-somename.yml
och testet laddar den här filen.