logo
down
shadow

Using mockito to test bigger services in Spring


Using mockito to test bigger services in Spring

By : NicoAriel
Date : November 21 2020, 04:01 AM
it helps some times As mentioned, you probably don't want the fields user, shoppingList and meals in your service. These fields make the service unsafe to use in a multi-threaded environment, like a web app or web service (which can be accessed by multiple clients, so multiple threads, at the same time). For example the shoppingList you are working on might be cleared halfway through the process if another thread enters createShoppingList. Instead, make these fields local variables inside the createShoppingList method for now. If the logic becomes too complex and your service too large, you could extract it into a separate service or a helper class which is instantiated at the start of the method call and discarded at the end of it.
I always write unit tests as white-box tests for a single class. I try to cover every branch in the code if I can. You can check this by running the tests with coverage in IntelliJ. Note that black-box tests are also very useful, they focus on 'the contract' of a component. In my opinion unit tests are usually not suited for this, since the contract of a single class is normally not very interesting for the component's functionality as a whole and can easily change if the code is refactored. I write integration (or end-to-end) tests as black box tests. This requires setting up a stubbed application environment with for example an in-memory database and maybe some external services via WireMock. I you are interested in this, look into Google's contract testing or RestAssured framework.
code :
public Map<Ingredient,Long> createShoppingList() {

// if any of the chained methods below return null, a NullPointerException occurs
// You could extract a method which takes the userInfoService user as an argument, see `findUser` below.
    user = userRepository.findByLoginAndPassword(userInfoService.getUser().getLogin(),userInfoService.getUser().getPassword()).get();

// the above would then  become:
    User user = findUser(userInfoService.getUser()).orElseThrow(new ShoppingServiceException("User not found");

// instead of clearing these field, just initialize them as local variables:       
    shoppingList.clear();
    meals.clear();

    meals = user.getDiet().getMeals();

// I would change adjustIngredients so it doesn't return the meals but void
// it's expected that such a method modifies the meals without making a copy
    meals = dietMealsService.adjustIngredients(meals);

// I would extract the below iteration into a separate method for clarity
    for (MealInfo meal : meals) {

// I would also extract the processing of a single meal into a separate method
// the `meal.getIngredients` actually doesn't return Ingredients but IngredientWeights
// this is very confusing, I would rename the field to `ingredientWeights`
        meal.getMeal().getIngredients().forEach(s -> {
// I would replace the four calls to s.getIngredient() with one call and a local variable
// and probably extract another method here
// You are using Ingredient as the key of a Map so you must implement
// `equals` and // `hashCode`. Otherwise you will be in for nasty 
// surprises later when Java doesn't see your identical ingredients as 
// equal. The simplest would be to use the database ID to determine equality.
            if(shoppingList.containsKey(s.getIngredient()))
                shoppingList.put(s.getIngredient(), s.getWeight()+shoppingList.get(s.getIngredient()));
            else
            shoppingList.put(s.getIngredient(),s.getWeight());
        });
    }
    return shoppingList;
}


private Optional<User> findUser(my.service.User user) {
    if (user != null) {
        return userRepository.findByLoginAndPassword(user.getLogin(), user.getPassword());
    }
    else {
        return Optional.empty();
    }
}

private void processMeals(List<MealInfo> meals, Map<Ingredient, Long> shoppingList) {
    for (MealInfo mealInfo : meals) {
        processIngredientWeights(mealInfo.getMeal().getIngredients(), shoppingList);
    }
}

private void processIngredientWeights(List<IngredientWeight> ingredientWeights, Map<Ingredient, Long> shoppingList) {
    for (IngredientWeight ingredientWeight: ingredientWeights) {            
        processIngredientWeight(ingredientWeight, shoppingList);
    }
}

private void processIngredientWeight(IngredientWeight ingredientWeight, Map<Ingredient, Long> shoppingList) {          
    Ingredient ingredient = ingredientWeight.getIngredient();
    Long weight = shoppingList.getOrDefault(ingredient, 0L);
    weight += ingredientWeight.getWeight();
    shoppingList.put(ingredient, weight);
}
MealInfo -> Meal
Meal -> Recipe (with a list of Ingredients)
IngredientInfo -> Ingredient (represents a certain amount of a FoodItem)
Ingredient -> FoodItem (e.g. 'broccoli')
public class ShoppingListService {

    private DietMealsService dietMealsService;

    public ShoppingListService(DietMealsService dietMealsService) {
        this.dietMealsService = dietMealsService;
    }

    public ShoppingList createShoppingList(User user) {
        List<Meal> meals = getMeals(user);
        dietMealsService.adjustIngredients(meals);
        return createShoppingList(meals);
    }

    private List<Meal> getMeals(User user) {
        Diet diet = user.getDiet();
        if (diet == null || diet.getMeals() == null || diet.getMeals().isEmpty()) {
            throw new ShoppingServiceException("User doesn't have diet");
        }
        return diet.getMeals();
    }

    private ShoppingList createShoppingList(List<Meal> meals) {
        ShoppingList shoppingList = new ShoppingList();
        for (Meal meal : meals) {
            processIngredientWeights(meal.getRecipe().getIngredients(), shoppingList);
        }
        return shoppingList;
    }

    private void processIngredientWeights(List<Ingredient> ingredients, ShoppingList shoppingList) {
        for (Ingredient ingredient : ingredients) {
            shoppingList.addWeight(ingredient);
        }
    }

}
import lombok.Data;

@Data
public class ShoppingList {

    private final Map<FoodItem, Long> ingredientWeights = new HashMap<>();

    public void addWeight(Ingredient ingredient) {
        FoodItem foodItem = ingredient.getFoodItem();
        Long weight = ingredientWeights.getOrDefault(foodItem, 0L);
        weight += ingredient.getWeight();
        ingredientWeights.put(foodItem, weight);
    }
}
@RunWith(MockitoJUnitRunner.class)
public class ShoppingListServiceTest {

    @InjectMocks
    private ShoppingListService instanceUnderTest;

    @Mock
    private DietMealsService dietMealsService;
    @Mock
    private User user;
    @Mock
    private Diet diet;
    @Mock
    private Meal meal;

    @Test(expected = ShoppingServiceException.class)
    public void testCreateShoppingListUserDietNull() {
        // SETUP
        User user = mock(User.class);
        when(user.getDiet()).thenReturn(null);

        // CALL
        instanceUnderTest.createShoppingList(user);
    }

    @Test(expected = ShoppingServiceException.class)
    public void testCreateShoppingListUserDietMealsNull() {
        // SETUP
        when(user.getDiet()).thenReturn(diet);
        when(diet.getMeals()).thenReturn(null);

        // CALL
        instanceUnderTest.createShoppingList(user);
    }

    @Test(expected = ShoppingServiceException.class)
    public void testCreateShoppingListUserDietMealsEmpty() {
        // SETUP
        when(user.getDiet()).thenReturn(diet);
        List<Meal> meals = new ArrayList<>();
        when(diet.getMeals()).thenReturn(meals);

        // CALL
        instanceUnderTest.createShoppingList(user);
    }


    @Test
    public void testCreateShoppingListAdjustsIngredients() {
        // SETUP
        when(user.getDiet()).thenReturn(diet);
        List<Meal> meals = Collections.singletonList(meal);
        when(diet.getMeals()).thenReturn(meals);

        // CALL
        instanceUnderTest.createShoppingList(user);

        // VERIFY
        verify(dietMealsService).adjustIngredients(meals);
    }

    @Test
    public void testCreateShoppingListAddsWeights() {
        // SETUP
        when(user.getDiet()).thenReturn(diet);
        when(diet.getMeals()).thenReturn(Collections.singletonList(meal));
        Recipe recipe = mock(Recipe.class);
        when(meal.getRecipe()).thenReturn(recipe);
        Ingredient ingredient1 = mock(Ingredient.class);
        Ingredient ingredient2 = mock(Ingredient.class);
        when(recipe.getIngredients()).thenReturn(Arrays.asList(ingredient1, ingredient2));
        FoodItem foodItem = mock(FoodItem.class);
        when(ingredient1.getFoodItem()).thenReturn(foodItem);
        when(ingredient2.getFoodItem()).thenReturn(foodItem);
        Long weight1 = 42L;
        Long weight2 = 1337L;
        when(ingredient1.getWeight()).thenReturn(weight1);
        when(ingredient2.getWeight()).thenReturn(weight2);

        // CALL
        ShoppingList shoppingList = instanceUnderTest.createShoppingList(user);

        // VERIFY
        Long expectedWeight = weight1 + weight2;
        Long actualWeight = shoppingList.getIngredientWeights().get(foodItem);
        assertEquals(expectedWeight, actualWeight);
    }
}


Share : facebook icon twitter icon
Spring + Mockito test injection

Spring + Mockito test injection


By : user3661599
Date : March 29 2020, 07:55 AM
should help you out You don't want to test your interface: it contains no code at all. You want to test your implementation. So the setter is available. Just use it:
code :
@Test
public void testLogin() {
    MobileServiceImpl toTest = new MobileServiceImpl();
    toTest.setMobileDao(mockMobileDao);
    // TODO call the login method and check that it works as expected.
}
Strange issue with Mockito and Spring test MVC

Strange issue with Mockito and Spring test MVC


By : Congtac Net
Date : March 29 2020, 07:55 AM
this one helps. The issue is that the type of the argument was a long and I passed an int.
Changing to:
code :
when(advertisementService.advertisementExistsAndBelongsToMember(eq(222L), any(Member.class))).thenReturn(Boolean.TRUE);
@Test
public void shouldAllow() throws Exception {
    mockMvc.perform(get("/advertisement/family/edit/{advertisementId}", 222L))//
            .andDo(print())//
            .andExpect(status().isOk());
}
Spring Test + Mockito.mock - Spring fails because it tries to load the mocked bean @Autowired dependencies

Spring Test + Mockito.mock - Spring fails because it tries to load the mocked bean @Autowired dependencies


By : suji
Date : March 29 2020, 07:55 AM
fixed the issue. Will look into that further When mocking a class using Mockito (or any other mocking framework) that class is still an instance of the original class. With that comes that it also contains all the annotations and class information with it.
So when you create a mock of the class it still detects all annotations on it and tries to full fill that. I.e. @Autowire other instances.
Simple Mockito Test (Spring + Dao)

Simple Mockito Test (Spring + Dao)


By : Tanguan Lang
Date : March 29 2020, 07:55 AM
may help you . By writing the following statements you are creating a new object of class AssetClass:
code :
AssetClass ac = new AssetClass();
@Autowired
private AssetClass ac;
@Mock
private AssetClass ac;
@Mock
private DataSource dataSource;

@Mock
private Connection conn;

...

Mockito.when(dataSource.getConnection()).thenReturn(conn);
Mock services inside another spring service with mockito

Mock services inside another spring service with mockito


By : MarcelMars
Date : March 29 2020, 07:55 AM
I wish this help you I'm facing problems mocking services injected inside of other services within the Spring framework. Here is my code: , You need to annotate ProductService with @InjectMocks:
Related Posts Related Posts :
  • Extracting data from HTML and formatting the output
  • SOLR documentCache JMX metrics clarification
  • Limiting Wildfly 14 Two-Way SSL to specific clients
  • How do I get Min and max values to only print when "year" is entered?
  • Hashmap can't loop - getKey() method not found - Using Java 8
  • Android Studio - Create an EditText with a click of a button
  • Mockito Test not invoking verify() method
  • Wrap method implementations of Java interfaces
  • Remediating dynamic SQL into prepared statements
  • Where do X and Y start at in swing windows
  • java code with files work from eclipse but dont work from cmd
  • Return page object from JPA query
  • I can't figure out why this code in my APCS multiple choice book returns 19
  • How to save data between methods
  • I'm trying to install Apache Gobblin. How can I install it using Gradle?
  • Spring Data Sorting Array or Set into Pageable
  • Question about the Java documentation and its implementation
  • How to make a JButton that when pressed it does a new action
  • Java hibernate No validator could be found for boolean
  • Making a POJO Thread Safe
  • Save the data of a text file in a arraylist
  • Sort a List<String[]> by indices using Comparator
  • Overloading in Java for user input?
  • Unable to format timestamp as YYYY-MM-DD HH:mm:ss in java
  • Access SQLite Helper From Adapter
  • How to stream a csv file with header to a HashMap<String, Double> in Java?
  • can't get go daddy ssl certificate to work with spring boot
  • ResourceBundle can't find BaseName gradle project java
  • Java; Jackson; Parsing the array of array json string
  • Java - map key lookup ignoring case
  • Jackson deserialize map null values to empty string
  • Anyone knows why setCount() is not working in twitter4j?
  • Object Visibility in a Multi-threaded Program in Java
  • Can't store and load an arraylist in an object file
  • convert a string number starts with `00` to `+` in java
  • Java - avoiding NonSuchElementException using ConcurrentLinkedDeque
  • Converting Immutable to mutable list Java
  • Getting nosuchmethod exception
  • How to get MQTT subscriptions
  • Android Google Sign in Exceptions
  • JavaFX - method that waits for user input
  • Replacing values for a particular key in treemap changes values for every key
  • This method call passes a null value for a nonnull method parameter. Either the parameter is annotated as a parameter th
  • Kafka: consume all messages on demand
  • Notify what text was changed in textview
  • Tinkerpop/Gremlin: select vertices together with outgoing edge count
  • transform a list of objects into a list of integers that pass a check
  • Why this java code is showing strange behavior?
  • Maven Project classes not compiling
  • Edit image to make text more clear opencv
  • Android Spinner nullpointer
  • Add result to int array every time you finish counting the occurrence
  • Android import java library
  • How to use LDAP Authentication in a corporate environment
  • adding item during iteration in java special usecase
  • How can I sort a map with string key? like (1 foo , 2 foo)
  • How to test an implementation of TLS based on SSLEngine?
  • Sorting a Linked List in alphabetical order
  • Can't make more than one request on java.net.http.HttpClient or will receive: javax.net.ssl.SSLHandshakeException
  • Java logic - strange things happening in while loop
  • shadow
    Privacy Policy - Terms - Contact Us © bighow.org