Modern unit és integrációs tesztelés HOUG Orákulum - 2016. április Viczián István Java fejlesztő - IP Systems @vicziani at Twitter http://jtechlog.hu
Miről lesz szó? 1 / 26 Automatizált tesztelés fontossága Unit és integrációs tesztek Élő dokumentáció Példaprojekt: https://github.com/vicziani/spring-training
Gyors 2 / 26
Tesztelendő unit 3 / 26 Coord public static Coord parse(string s) { String[] items = s.split(","); if (items.length!= 2) { throw new IllegalArgumentException( String.format("Invalid coordinate: %s", s)); double lat = Double.parseDouble(items[0].trim()); double lon = Double.parseDouble(items[1].trim()); return new Coord(lat, lon);
Unit teszt 4 / 26 CoordTest @Test public void shouldparse() { String position = "47.4811281,18.9902207"; Coord coord = Coord.parse(position); assertthat(coord.getlat(), is(47.4811281)); assertthat(coord.getlon(), is(18.9902207));
Unit teszt Hamcresttel 5 / 26 CoordTest @Test public void shouldparseassertwithmatcher() { String position = "47.4811281,18.9902207"; assertthat(coord.parse(position), iscoord(is(47.4811281), is(18.9902207)));
Unit teszt rule-lal 6 / 26 CoordTest @Rule public ExpectedException thrown = ExpectedException.none(); @Test public void shoudthrowillegalargumentexception() { String position = "abc"; thrown.expect(illegalargumentexception.class); thrown.expectmessage(is("invalid coordinate: abc")); Coord.parse(position);
Paraméterezett unit teszt 7 / 26 CoordParametrizedTest @Parameterized.Parameters(name = "{index: Coord.parse for {0 throws {1") public static Collection<Object[]> data() { return Arrays.asList(new Object[][] { { null, NullPointerException.class, { "", IllegalArgumentException.class, { "1", IllegalArgumentException.class, { "1,2,3", IllegalArgumentException.class, { "1,a", NumberFormatException.class, { "a,1", NumberFormatException.class, { ",1", NumberFormatException.class, { ",,", IllegalArgumentException.class );
Biztosítja a struktúrát 8 / 26
Nem unit tesztelhető 9 / 26 public Page<LocationDto> listlocations(pageable pageable) { return new LocationRepositoryImpl().findAll(pageable).map(new LocationDtoConverter());
Tesztelhető 10 / 26 LocationService public class LocationService { private LocationRepository locationrepository; @Autowired public LocationService(LocationRepository locationrepository) { this.locationrepository = locationrepository; public Page<LocationDto> listlocations(pageable pageable) { return locationrepository.findall(pageable).map(new LocationDtoConverter());
Teszt Mockitoval 11 / 26 LocationServiceTest @RunWith(MockitoJUnitRunner.class) public class LocationServiceTest { @Mock LocationRepository locationrepository; @InjectMocks LocationService locationservice; @Test public void shouldcallsave() { locationservice.createlocation( new CreateLocationDto("Budapest", "47.4811281,18.9902207")); verify(locationrepository).save( (Location) argthat(hasproperty("name", is("budapest"))));
Biztonságos 12 / 26
Refaktoring 13 / 26 Olvashatóság Komplexitás csökkentése Kód befogadás Teszt - refaktoring - teszt
Unit vagy integrációs teszt? 14 / 26
Integrációs teszt 15 / 26 Teszt piramis? Minden teszteset előtt adatbázis törlés Alapadatok feltöltése az alkalmazáson keresztül
Integrációs teszt controlleren 16 / 26 LocationControllerIntegrationTest @Test public void aftersaveshouldquery() { CreateLocationDto createlocationdto = new CreateLocationDto("Budapest", "47.4811281,18.9902207"); locationcontroller.postsavelocation(createlocationdto, new BeanPropertyBindingResult(createLocationDto, "createlocationdto"), new PageRequest(0, 50), new RedirectAttributesModelMap()); ModelAndView modelandview = locationcontroller.getlistlocations(new PageRequest(0, 50)); List<LocationDto> locations = ((Page<LocationDto>) modelandview.getmodelmap().get("locations")).getcontent(); assertthat(locations, hassize(1)); assertthat(locations, hasitem(locationwithname(is("budapest")).withlat(is(47.4811281)).withlon(is(18.9902207))));
Integrációs teszt Spring Mock MVC-vel 17 / 26 LocationControllerMockMvcIntegrationTest @Test public void aftersaveshouldquery() throws Exception { mockmvc.perform(post("/").param("name", "Budapest").param("position", "47.4811281,18.9902207")).andExpect(status().is3xxRedirection()); mockmvc.perform(get("/")).andexpect(status().isok()).andexpect(model().attribute("locations", hasitem(locationwithname(is("budapest")).withlat(is(47.4811281)).withlon(is(18.9902207)))));
Integrációs teszt, assert a renderelt view-n 18 / 26 LocationControllerMockMvcIntegrationTest mockmvc.perform(get("/")).andexpect(status().isok()).andexpect(content().string(containsstring("budapest")));
Integrációs teszt rest controlleren 19 / 26 LocationRestControllerIntegrationTest @Test public void aftersaveshouldquery() { locationrestcontroller.postsavelocation( new CreateLocationDto("Budapest", "47.4811281,18.9902207")); List<LocationDto> locations = locationrestcontroller.getlistlocations( new PageRequest(0, 50)).getContent(); assertthat(locations, hassize(1)); assertthat(locations, hasitem(locationwithname(is("budapest")).withlat(is(47.4811281)).withlon(is(18.9902207))));
Integrációs teszt Mock Mvc-vel 20 / 26 LocationRestControllerMockMvcIntegrationTest @Test public void aftersaveshouldquery() throws Exception { mockmvc.perform(post("/api/locations").param("name", "Budapest").param("position", "47.4811281,18.9902207")).andExpect(status().isOk()); mockmvc.perform(get("/api/locations")).andexpect(status().isok()).andexpect(jsonpath("$.content[0].name", is("budapest"))).andexpect(jsonpath("$.content[0].lat", is(47.4811281))).andexpect(jsonpath("$.content[0].lon", is(18.9902207)));
Integrációs tesztelés driverrel 21 / 26 LocationRestControllerDriverIntegrationTest @Test public void aftersaveshouldquery() { locationdriver.newlocation().withname("budapest").withposition("47.4811281,18.9902207").create().listlocations().locationssize(1).haslocation(locationwithname(is("budapest")).withlat(is(47.4811281)).withlon(is(18.9902207)));
Élő dokumentáció 22 / 26
Concordion 23 / 26 HTML dokumentáció, mögötte integrációs tesztek Hiba esetén színezés Szétválik a dokumentációs és kód Szétválik a funkció leírása és a példa Nem kötött formátum Dokumentáció generálható
Concordion HTML 24 / 26 Location.html <p concordion:execute="savelocation(#name, #position)"> Felveszek egy új helyet <span concordion:set="#name">budapest</span> névvel <span concordion:set="#position">47.4811281, 18.9902207</span> koordinátával.</p> <p><span concordion:execute="querybyname(#name)"/> Ha lekérdezem a megadott névvel, a szélességi fok <span concordion:assertequals="getlat()">47.4811281</span>, és a hosszúsági fok <span concordion:assertequals="getlon()">18.9902207</span> lesz.</p>
Concordion Java teszt 25 / 26 LocationTest public void savelocation(string name, String position) { locationdriver.newlocation().withname(name).withposition(position).create(); public void querybyname(string name) { locationdto = locationdriver.listlocations().findbyname(name); public double getlat() { return locationdto.lat; public double getlon() { return locationdto.lon;