티스토리 뷰

728x90

1. 이 포스트는 JUnit 4 버전으로 작성되었다.

 

2. Integration Test를 위해서는 Application Context를 생성하여 한다. 

  2-1 이것을 위해 @RunWith라는 annotation으로 테스트를 수행하는 지정된 클래스를 실행하게 된다.

  2-2 테스트를 위한 간단한 Context를 실행한다고 생각할 수 있고, 보통 JUnit 4에서는 SpringRunner.class가 지정된다.

  2-3 SpringRunner.class는 이전에 SpringJUnit4ClassRunner의 이름만 바꾼거다.

 

3. Mongo DB 테스트를 위하여 @DataMongoTest라는 것이 제공된다.

  3-1 내부적으로는 auto-configuration이 모두 disable되고 Mongo DB 테스트와 관련된 부분만 활성화 된다.

  3-2 @DataMongoTest은 트렌젝션의 개념이 존재하지 않기 때문에 실행 후에도 값이 남아 있게 된다.

    3-2-1 그렇기 때문에 setup에서 이전에 데이터를 모두 지워야 중복된 데이터가 저장되지 않는다.

  3-3 기본적으로 외부 설정 파일이나 자동설정기능에서 지정한 datasource는 무시되고 내장 데이터베이스를 사용한다.

  3-4 데이터베이스 테스트 기능 뿐 아니라 모든 스프링의 기능을 사용하면서 내장 데이터베이스를 사용하려면

    3-5-1 SpringBootTest, @AutoConfigureTestDatabase 함께 사용하여 설정할 수 있다.

 

4. 아래 소스를 보면 @DataMongoTest가 지정되어 Mongo DB테스트임을 알 수 있다.

 

package pe.pilseong.recipe.repository;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import pe.pilseong.recipe.bootstrap.RecipeBootstrap;
import pe.pilseong.recipe.domain.UnitOfMeasure;

@RunWith(SpringRunner.class)
@DataMongoTest
public class UnitOfMeasureRepositoryIT {

  @Autowired
  UnitOfMeasureRepository unitOfMeasureRepository;

  @Autowired
  CategoryRepository categoryRepository;

  @Autowired
  RecipeRepository recipeRepository;

  @Before
  public void setup() {
    recipeRepository.deleteAll();
    unitOfMeasureRepository.deleteAll();
    categoryRepository.deleteAll();

    RecipeBootstrap bootstrap = new RecipeBootstrap(categoryRepository, recipeRepository, unitOfMeasureRepository);
    bootstrap.onApplicationEvent(null);
  }

  @Test
  @DirtiesContext
  public void findbyDescription() {
    Optional<UnitOfMeasure> uom = unitOfMeasureRepository.findByDescription("Teaspoon");

    assertEquals("Teaspoon", uom.get().getDescription());
  }

  @Test
  @DirtiesContext
  public void findbyDescriptionCup() {
    Optional<UnitOfMeasure> uom = unitOfMeasureRepository.findByDescription("Cup");

    assertEquals("Cup", uom.get().getDescription());
  }

  @Test
  public void test() {

  }
}

 

  4-1 테스트를 구현할 때 미리 데이터가 데이터베이스에 들어 있어야 하는데 현재 ApplicationListener로 되어 있다.

    4-1-1 스프링 컨텍스트가 모두 생성되지 않기 때문에 이 초기화 클래스를 강제로 실행을 해야 한다.

    4-1-2 그래서 setup 메소드에 해당 클래스를 직접 생성하면서 필요한 인자들도 같이 가져와야 한다.

    4-1-3 RecipeBootstrap는 @Component이므로 그냥 @Autowired 하면 될 것 같은데 정상적으로 돌아가지가 않는다. 

      4-1-3-1 오류를 보면 해당 빈이 스프링 컨텍스트에 제대로 생성되지 않았다고 나와 있다.

 

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'pe.pilseong.recipe.bootstrap.RecipeBootstrap' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1714) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1270) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1224) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640) ~[spring-beans-5.2.7.RELEASE.jar:5.2.7.RELEASE]
	... 54 common frames omitted

 

package pe.pilseong.recipe.bootstrap;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import pe.pilseong.recipe.domain.Category;
import pe.pilseong.recipe.domain.Difficulty;
import pe.pilseong.recipe.domain.Ingredient;
import pe.pilseong.recipe.domain.Note;
import pe.pilseong.recipe.domain.Recipe;
import pe.pilseong.recipe.domain.UnitOfMeasure;
import pe.pilseong.recipe.repository.CategoryRepository;
import pe.pilseong.recipe.repository.RecipeRepository;
import pe.pilseong.recipe.repository.UnitOfMeasureRepository;

@Slf4j
@Component
@RequiredArgsConstructor
public class RecipeBootstrap implements ApplicationListener<ContextRefreshedEvent> {

  private final CategoryRepository categoryRepository;
  private final RecipeRepository recipeRepository;
  private final UnitOfMeasureRepository unitOfMeasureRepository;

  @Override
  public void onApplicationEvent(ContextRefreshedEvent event) {
    log.debug("onApplicationEvent in RecipeBootstrap");
    loadCategories();
    loadUom();
    recipeRepository.saveAll(getRecipes());
  }

  private void loadCategories() {
    Category cat1 = new Category();
    cat1.setDescription("American");
    categoryRepository.save(cat1);

    Category cat2 = new Category();
    cat2.setDescription("Italian");
    categoryRepository.save(cat2);

    Category cat3 = new Category();
    cat3.setDescription("Mexican");
    categoryRepository.save(cat3);

    Category cat4 = new Category();
    cat4.setDescription("Fast Food");
    categoryRepository.save(cat4);
  }

  private void loadUom() {
    UnitOfMeasure uom1 = new UnitOfMeasure();
    uom1.setDescription("Teaspoon");
    unitOfMeasureRepository.save(uom1);

    UnitOfMeasure uom2 = new UnitOfMeasure();
    uom2.setDescription("Tablespoon");
    unitOfMeasureRepository.save(uom2);

    UnitOfMeasure uom3 = new UnitOfMeasure();
    uom3.setDescription("Cup");
    unitOfMeasureRepository.save(uom3);

    UnitOfMeasure uom4 = new UnitOfMeasure();
    uom4.setDescription("Pinch");
    unitOfMeasureRepository.save(uom4);

    UnitOfMeasure uom5 = new UnitOfMeasure();
    uom5.setDescription("Ounce");
    unitOfMeasureRepository.save(uom5);

    UnitOfMeasure uom6 = new UnitOfMeasure();
    uom6.setDescription("Each");
    unitOfMeasureRepository.save(uom6);

    UnitOfMeasure uom7 = new UnitOfMeasure();
    uom7.setDescription("Pint");
    unitOfMeasureRepository.save(uom7);

    UnitOfMeasure uom8 = new UnitOfMeasure();
    uom8.setDescription("Dash");
    unitOfMeasureRepository.save(uom8);
  }

  private List<Recipe> getRecipes() {

    List<Recipe> recipes = new ArrayList<>(2);

    // get UOMs
    Optional<UnitOfMeasure> eachUomOptional = unitOfMeasureRepository.findByDescription("Each");

    if (!eachUomOptional.isPresent()) {
      throw new RuntimeException("Expected UOM Not Found");
    }

    Optional<UnitOfMeasure> tableSpoonUomOptional = unitOfMeasureRepository.findByDescription("Tablespoon");

    if (!tableSpoonUomOptional.isPresent()) {
      throw new RuntimeException("Expected UOM Not Found");
    }

    Optional<UnitOfMeasure> teaSpoonUomOptional = unitOfMeasureRepository.findByDescription("Teaspoon");

    if (!teaSpoonUomOptional.isPresent()) {
      throw new RuntimeException("Expected UOM Not Found");
    }

    Optional<UnitOfMeasure> dashUomOptional = unitOfMeasureRepository.findByDescription("Dash");

    if (!dashUomOptional.isPresent()) {
      throw new RuntimeException("Expected UOM Not Found");
    }

    Optional<UnitOfMeasure> pintUomOptional = unitOfMeasureRepository.findByDescription("Pint");

    if (!pintUomOptional.isPresent()) {
      throw new RuntimeException("Expected UOM Not Found");
    }

    Optional<UnitOfMeasure> cupsUomOptional = unitOfMeasureRepository.findByDescription("Cup");

    if (!cupsUomOptional.isPresent()) {
      throw new RuntimeException("Expected UOM Not Found");
    }

    // get optionals
    UnitOfMeasure eachUom = eachUomOptional.get();
    UnitOfMeasure tableSpoonUom = tableSpoonUomOptional.get();
    UnitOfMeasure teapoonUom = tableSpoonUomOptional.get();
    UnitOfMeasure dashUom = dashUomOptional.get();
    UnitOfMeasure pintUom = pintUomOptional.get();
    UnitOfMeasure cupsUom = cupsUomOptional.get();

    // get Categories
    Optional<Category> americanCategoryOptional = categoryRepository.findByDescription("American");

    if (!americanCategoryOptional.isPresent()) {
      throw new RuntimeException("Expected Category Not Found");
    }

    Optional<Category> mexicanCategoryOptional = categoryRepository.findByDescription("Mexican");

    if (!mexicanCategoryOptional.isPresent()) {
      throw new RuntimeException("Expected Category Not Found");
    }

    Category americanCategory = americanCategoryOptional.get();
    Category mexicanCategory = mexicanCategoryOptional.get();

    //Yummy Guac
    Recipe guacRecipe = Recipe.builder().build();
    guacRecipe.setDescription("Perfect Guacamole");
    guacRecipe.setPrepTime(10);
    guacRecipe.setCookTime(0);
    guacRecipe.setDifficulty(Difficulty.EASY);
    guacRecipe.setDirections("1 Cut avocado, remove flesh: Cut the avocados in half. Remove seed. Score the inside of the avocado with a blunt knife and scoop out the flesh with a spoon"
        + "\n"
        + "2 Mash with a fork: Using a fork, roughly mash the avocado. (Don't overdo it! The guacamole should be a little chunky.)"
        + "\n"
        + "3 Add salt, lime juice, and the rest: Sprinkle with salt and lime (or lemon) juice. The acid in the lime juice will provide some balance to the richness of the avocado and will help delay the avocados from turning brown.\n"
        + "Add the chopped onion, cilantro, black pepper, and chiles. Chili peppers vary individually in their hotness. So, start with a half of one chili pepper and add to the guacamole to your desired degree of hotness.\n"
        + "Remember that much of this is done to taste because of the variability in the fresh ingredients. Start with this recipe and adjust to your taste.\n"
        + "4 Cover with plastic and chill to store: Place plastic wrap on the surface of the guacamole cover it and to prevent air reaching it. (The oxygen in the air causes oxidation which will turn the guacamole brown.) Refrigerate until ready to serve.\n"
        + "Chilling tomatoes hurts their flavor, so if you want to add chopped tomato to your guacamole, add it just before serving.\n"
        + "\n"
        + "\n"
        + "Read more: http://www.simplyrecipes.com/recipes/perfect_guacamole/#ixzz4jvpiV9Sd");

    Note guacNotes = new Note();
    guacNotes.setRecipeNote("For a very quick guacamole just take a 1/4 cup of salsa and mix it in with your mashed avocados.\n"
        + "Feel free to experiment! One classic Mexican guacamole has pomegranate seeds and chunks of peaches in it (a Diana Kennedy favorite). Try guacamole with added pineapple, mango, or strawberries.\n"
        + "The simplest version of guacamole is just mashed avocados with salt. Don't let the lack of availability of other ingredients stop you from making guacamole.\n"
        + "To extend a limited supply of avocados, add either sour cream or cottage cheese to your guacamole dip. Purists may be horrified, but so what? It tastes great.\n"
        + "\n"
        + "\n"
        + "Read more: http://www.simplyrecipes.com/recipes/perfect_guacamole/#ixzz4jvoun5ws");
    guacRecipe.setNote(guacNotes);

    guacRecipe.addIngredient(new Ingredient("ripe avocados", new BigDecimal(2), eachUom));
    guacRecipe.addIngredient(new Ingredient("Kosher salt", new BigDecimal(".5"), teapoonUom));
    guacRecipe.addIngredient(new Ingredient("fresh lime juice or lemon juice", new BigDecimal(2), tableSpoonUom));
    guacRecipe.addIngredient(new Ingredient("minced red onion or thinly sliced green onion", new BigDecimal(2), tableSpoonUom));
    guacRecipe.addIngredient(new Ingredient("serrano chiles, stems and seeds removed, minced", new BigDecimal(2), eachUom));
    guacRecipe.addIngredient(new Ingredient("Cilantro", new BigDecimal(2), tableSpoonUom));
    guacRecipe.addIngredient(new Ingredient("freshly grated black pepper", new BigDecimal(2), dashUom));
    guacRecipe.addIngredient(new Ingredient("ripe tomato, seeds and pulp removed, chopped", new BigDecimal(".5"), eachUom));

    guacRecipe.getCategories().add(americanCategory);
    guacRecipe.getCategories().add(mexicanCategory);

    guacRecipe.setUrl("http://www.simplerecipes.com/recipes/perfect_guacamole/");
    guacRecipe.setServings(4);
    guacRecipe.setSource("Simply Recipes");

    //add to return list
    recipes.add(guacRecipe);

    //Yummy Tacos
    Recipe tacosRecipe = Recipe.builder().build();
    tacosRecipe.setDescription("Spicy Grilled Chicken Taco");
    tacosRecipe.setCookTime(9);
    tacosRecipe.setPrepTime(20);
    tacosRecipe.setDifficulty(Difficulty.MODERATE);

    tacosRecipe.setDirections("1 Prepare a gas or charcoal grill for medium-high, direct heat.\n"
        + "2 Make the marinade and coat the chicken: In a large bowl, stir together the chili powder, oregano, cumin, sugar, salt, garlic and orange zest. Stir in the orange juice and olive oil to make a loose paste. Add the chicken to the bowl and toss to coat all over.\n"
        + "Set aside to marinate while the grill heats and you prepare the rest of the toppings.\n"
        + "\n"
        + "\n"
        + "3 Grill the chicken: Grill the chicken for 3 to 4 minutes per side, or until a thermometer inserted into the thickest part of the meat registers 165F. Transfer to a plate and rest for 5 minutes.\n"
        + "4 Warm the tortillas: Place each tortilla on the grill or on a hot, dry skillet over medium-high heat. As soon as you see pockets of the air start to puff up in the tortilla, turn it with tongs and heat for a few seconds on the other side.\n"
        + "Wrap warmed tortillas in a tea towel to keep them warm until serving.\n"
        + "5 Assemble the tacos: Slice the chicken into strips. On each tortilla, place a small handful of arugula. Top with chicken slices, sliced avocado, radishes, tomatoes, and onion slices. Drizzle with the thinned sour cream. Serve with lime wedges.\n"
        + "\n"
        + "\n"
        + "Read more: http://www.simplyrecipes.com/recipes/spicy_grilled_chicken_tacos/#ixzz4jvtrAnNm");

    Note tacoNotes = new Note();
    tacoNotes.setRecipeNote("We have a family motto and it is this: Everything goes better in a tortilla.\n"
        + "Any and every kind of leftover can go inside a warm tortilla, usually with a healthy dose of pickled jalapenos. I can always sniff out a late-night snacker when the aroma of tortillas heating in a hot pan on the stove comes wafting through the house.\n"
        + "Today's tacos are more purposeful ?? a deliberate meal instead of a secretive midnight snack!\n"
        + "First, I marinate the chicken briefly in a spicy paste of ancho chile powder, oregano, cumin, and sweet orange juice while the grill is heating. You can also use this time to prepare the taco toppings.\n"
        + "Grill the chicken, then let it rest while you warm the tortillas. Now you are ready to assemble the tacos and dig in. The whole meal comes together in about 30 minutes!\n"
        + "\n"
        + "\n"
        + "Read more: http://www.simplyrecipes.com/recipes/spicy_grilled_chicken_tacos/#ixzz4jvu7Q0MJ");
    tacosRecipe.setNote(tacoNotes);

    tacosRecipe.addIngredient(new Ingredient("Ancho Chili Powder", new BigDecimal(2), tableSpoonUom));
    tacosRecipe.addIngredient(new Ingredient("Dried Oregano", new BigDecimal(1), teapoonUom));
    tacosRecipe.addIngredient(new Ingredient("Dried Cumin", new BigDecimal(1), teapoonUom));
    tacosRecipe.addIngredient(new Ingredient("Sugar", new BigDecimal(1), teapoonUom));
    tacosRecipe.addIngredient(new Ingredient("Salt", new BigDecimal(".5"), teapoonUom));
    tacosRecipe.addIngredient(new Ingredient("Clove of Garlic, Choppedr", new BigDecimal(1), eachUom));
    tacosRecipe.addIngredient(new Ingredient("finely grated orange zestr", new BigDecimal(1), tableSpoonUom));
    tacosRecipe.addIngredient(new Ingredient("fresh-squeezed orange juice", new BigDecimal(3), tableSpoonUom));
    tacosRecipe.addIngredient(new Ingredient("Olive Oil", new BigDecimal(2), tableSpoonUom));
    tacosRecipe.addIngredient(new Ingredient("boneless chicken thighs", new BigDecimal(4), tableSpoonUom));
    tacosRecipe.addIngredient(new Ingredient("small corn tortillasr", new BigDecimal(8), eachUom));
    tacosRecipe.addIngredient(new Ingredient("packed baby arugula", new BigDecimal(3), cupsUom));
    tacosRecipe.addIngredient(new Ingredient("medium ripe avocados, slic", new BigDecimal(2), eachUom));
    tacosRecipe.addIngredient(new Ingredient("radishes, thinly sliced", new BigDecimal(4), eachUom));
    tacosRecipe.addIngredient(new Ingredient("cherry tomatoes, halved", new BigDecimal(".5"), pintUom));
    tacosRecipe.addIngredient(new Ingredient("red onion, thinly sliced", new BigDecimal(".25"), eachUom));
    tacosRecipe.addIngredient(new Ingredient("Roughly chopped cilantro", new BigDecimal(4), eachUom));
    tacosRecipe.addIngredient(new Ingredient("cup sour cream thinned with 1/4 cup milk", new BigDecimal(4), cupsUom));
    tacosRecipe.addIngredient(new Ingredient("lime, cut into wedges", new BigDecimal(4), eachUom));

    tacosRecipe.getCategories().add(americanCategory);
    tacosRecipe.getCategories().add(mexicanCategory);

    recipes.add(tacosRecipe);
    return recipes;
  }
}
728x90
댓글