DEV Community

Swapnil Gupta
Swapnil Gupta

Posted on

Mockito example

Certainly! Here's an example of testing a private method and switch cases using only Mockito:

public class DiscountService {

    public double calculateDiscount(CustomerType customerType, double totalPrice) {
        double discountPercentage = calculateDiscountPercentage(customerType);
        return totalPrice - (totalPrice * discountPercentage);
    }

    private double calculateDiscountPercentage(CustomerType customerType) {
        switch (customerType) {
            case REGULAR:
                return 0.1;
            case PREMIUM:
                return 0.2;
            case VIP:
                return 0.3;
            default:
                throw new IllegalArgumentException("Invalid customer type: " + customerType);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

And here's the corresponding test using Mockito:

@RunWith(MockitoJUnitRunner.class)
public class DiscountServiceTest {

    private DiscountService discountService;

    @Before
    public void setUp() {
        discountService = Mockito.spy(new DiscountService());
    }

    @Test
    public void testCalculateDiscount_RegularCustomer() throws Exception {
        // Arrange
        CustomerType customerType = CustomerType.REGULAR;
        double totalPrice = 100.0;

        Mockito.doReturn(0.1).when(discountService).calculateDiscountPercentage(customerType);

        // Act
        double discountedPrice = discountService.calculateDiscount(customerType, totalPrice);

        // Assert
        assertEquals(90.0, discountedPrice, 0.01);
        Mockito.verify(discountService, Mockito.times(1))
                .calculateDiscountPercentage(customerType);
    }

    // Additional test cases for other customer types
}
Enter fullscreen mode Exit fullscreen mode

In this example:

  • We use the MockitoJUnitRunner and @Before annotation to set up the test.
  • We create a spy object for the DiscountService using Mockito.spy() to allow us to mock the private method.
  • We use Mockito.doReturn(0.1).when(discountService).calculateDiscountPercentage(customerType) to mock the behavior of the private method based on the customer type.
  • We invoke the calculateDiscount() method and verify that the discounted price is calculated correctly.
  • We use Mockito.verify(discountService, Mockito.times(1)).calculateDiscountPercentage(customerType) to verify that the private method was called with the correct arguments.

Again, note that testing private methods directly is generally not recommended. It is preferable to test the behavior of the private method indirectly by testing the public methods that rely on it.

Certainly! Here's a step-by-step explanation of how to test a private method and switch cases using Mockito:

  1. Set up the Test Environment:
    • Annotate your test class with @RunWith(MockitoJUnitRunner.class) to use the Mockito test runner.
    • Create an instance of the class you want to test, in this case, DiscountService.
    • Use Mockito.spy() to create a spy object that allows you to mock the behavior of the private method.
@RunWith(MockitoJUnitRunner.class)
public class DiscountServiceTest {

    private DiscountService discountService;

    @Before
    public void setUp() {
        discountService = Mockito.spy(new DiscountService());
    }

    // Rest of the test methods...
}
Enter fullscreen mode Exit fullscreen mode
  1. Mock the Private Method Behavior:
    • Use Mockito.doReturn() to define the behavior of the private method when called with specific arguments.
@Test
public void testCalculateDiscount_RegularCustomer() throws Exception {
    // Arrange
    CustomerType customerType = CustomerType.REGULAR;
    double totalPrice = 100.0;

    Mockito.doReturn(0.1).when(discountService).calculateDiscountPercentage(customerType);

    // Act
    double discountedPrice = discountService.calculateDiscount(customerType, totalPrice);

    // Assert
    assertEquals(90.0, discountedPrice, 0.01);
    Mockito.verify(discountService, Mockito.times(1)).calculateDiscountPercentage(customerType);
}
Enter fullscreen mode Exit fullscreen mode
  1. Invoke the Public Method and Verify Results:
    • Invoke the public method you want to test, such as calculateDiscount(), with the necessary arguments.
    • Use assertions to verify that the expected results are obtained.
    • Use Mockito.verify() to ensure that the private method was called with the correct arguments.
// ...

@Test
public void testCalculateDiscount_RegularCustomer() throws Exception {
    // Arrange
    CustomerType customerType = CustomerType.REGULAR;
    double totalPrice = 100.0;

    Mockito.doReturn(0.1).when(discountService).calculateDiscountPercentage(customerType);

    // Act
    double discountedPrice = discountService.calculateDiscount(customerType, totalPrice);

    // Assert
    assertEquals(90.0, discountedPrice, 0.01);
    Mockito.verify(discountService, Mockito.times(1)).calculateDiscountPercentage(customerType);
}

// ...
Enter fullscreen mode Exit fullscreen mode

By following these steps, you can effectively test a private method and switch cases using Mockito. Remember that while testing private methods directly is possible with Mockito, it is generally recommended to focus on testing the behavior of public methods that rely on the private logic. This approach ensures that the desired behavior is tested through the public interface of your classes.

Example 2

Certainly! Here's an example that demonstrates how to test a private method with switch cases using Mockito's spy():

Consider a PaymentService class that processes payments based on different payment methods. The class has a private method, calculateFee, which calculates the fee based on the selected payment method.

public class PaymentService {

    public double processPayment(double amount, PaymentMethod paymentMethod) {
        double fee = calculateFee(paymentMethod);
        return amount + fee;
    }

    private double calculateFee(PaymentMethod paymentMethod) {
        double fee;
        switch (paymentMethod) {
            case CREDIT_CARD:
                fee = 0.02;
                break;
            case DEBIT_CARD:
                fee = 0.01;
                break;
            case PAYPAL:
                fee = 0.03;
                break;
            default:
                throw new IllegalArgumentException("Invalid payment method: " + paymentMethod);
        }
        return fee;
    }
}
Enter fullscreen mode Exit fullscreen mode

To test the private method calculateFee with switch cases, we can use the spy() method and Mockito.doCallRealMethod():

import org.mockito.Mockito;

public class PaymentServiceTest {

    @Test
    public void testCalculateFee() throws Exception {
        // Create a spy object of the PaymentService class
        PaymentService paymentService = Mockito.spy(new PaymentService());

        // Call the private method directly using Mockito.doCallRealMethod()
        double fee = Mockito.doCallRealMethod()
                .when(paymentService)
                .calculateFee(Mockito.any(PaymentMethod.class));

        // Assert the fee value for different payment methods
        assertEquals(0.02, paymentService.calculateFee(PaymentMethod.CREDIT_CARD), 0.01);
        assertEquals(0.01, paymentService.calculateFee(PaymentMethod.DEBIT_CARD), 0.01);
        assertEquals(0.03, paymentService.calculateFee(PaymentMethod.PAYPAL), 0.01);
    }
}
Enter fullscreen mode Exit fullscreen mode

In this example:

  • We create a spy object of the PaymentService class using Mockito.spy(new PaymentService()).
  • We use Mockito.doCallRealMethod() to instruct Mockito to call the real implementation of the private method when it's invoked.
  • We assert the fee value returned by the calculateFee() method for different payment methods.

Note that in this example, we're testing the private method indirectly by invoking the public method that depends on it. By using spy() and doCallRealMethod(), we can ensure that the private method is executed with its real implementation while testing the overall behavior of the public method.

Remember that testing private methods directly is generally not recommended. It's preferable to focus on testing the behavior of public methods that rely on the private logic to ensure comprehensive testing.

Certainly! Here's a step-by-step explanation of how to test a private method with switch cases using Mockito's spy():

  1. Create a Spy Object:
    • To test a private method, we need to create a spy object using Mockito.spy().
    • A spy object wraps an existing instance of a class and allows us to mock specific behaviors while still retaining the original functionality.
    • In our example, we'll create a spy object of the PaymentService class.
PaymentService paymentService = Mockito.spy(new PaymentService());
Enter fullscreen mode Exit fullscreen mode
  1. Mock the Private Method Behavior:
    • We'll use Mockito.doCallRealMethod() to instruct Mockito to call the real implementation of the private method when it's invoked.
    • This allows us to test the private method indirectly by invoking the public method that depends on it.
    • In our example, we'll mock the behavior of the private method, calculateFee, which calculates the fee based on the payment method.
Mockito.doCallRealMethod()
       .when(paymentService)
       .calculateFee(Mockito.any(PaymentMethod.class));
Enter fullscreen mode Exit fullscreen mode
  1. Invoke the Public Method and Assert Results:
    • Since we've mocked the behavior of the private method, we can now invoke the public method that relies on it.
    • In our example, we'll call the calculateFee() method for different payment methods and assert the expected fee values.
    • We can use assertions, such as assertEquals, to verify that the fee values are as expected.
assertEquals(0.02, paymentService.calculateFee(PaymentMethod.CREDIT_CARD), 0.01);
assertEquals(0.01, paymentService.calculateFee(PaymentMethod.DEBIT_CARD), 0.01);
assertEquals(0.03, paymentService.calculateFee(PaymentMethod.PAYPAL), 0.01);
Enter fullscreen mode Exit fullscreen mode

In this scenario, by using spy() and doCallRealMethod(), we create a spy object of the class under test and allow the private method to be executed with its real implementation. This way, we can test the overall behavior of the public method while indirectly testing the private method with switch cases.

Remember that it's generally recommended to focus on testing the behavior of public methods that rely on the private logic rather than testing private methods directly. This approach ensures that the desired behavior is tested through the public interface of your classes.

Example 3

Certainly! Here's a more complex example that involves testing a private method with switch cases using Mockito's spy():

Consider a ShippingService class that calculates the shipping cost based on the destination and shipping method. The class has a private method, calculateCost, which calculates the cost based on the destination country and shipping method type.

public class ShippingService {

    public double calculateShippingCost(String destinationCountry, ShippingMethod shippingMethod, double weight) {
        double cost = calculateCost(destinationCountry, shippingMethod);
        return cost * weight;
    }

    private double calculateCost(String destinationCountry, ShippingMethod shippingMethod) {
        double cost;
        switch (destinationCountry) {
            case "USA":
                cost = calculateCostForUSAShipping(shippingMethod);
                break;
            case "Canada":
                cost = calculateCostForCanadaShipping(shippingMethod);
                break;
            case "UK":
                cost = calculateCostForUKShipping(shippingMethod);
                break;
            default:
                throw new IllegalArgumentException("Invalid destination country: " + destinationCountry);
        }
        return cost;
    }

    private double calculateCostForUSAShipping(ShippingMethod shippingMethod) {
        switch (shippingMethod) {
            case STANDARD:
                return 5.0;
            case EXPRESS:
                return 10.0;
            default:
                throw new IllegalArgumentException("Invalid shipping method: " + shippingMethod);
        }
    }

    private double calculateCostForCanadaShipping(ShippingMethod shippingMethod) {
        switch (shippingMethod) {
            case STANDARD:
                return 7.0;
            case EXPRESS:
                return 12.0;
            default:
                throw new IllegalArgumentException("Invalid shipping method: " + shippingMethod);
        }
    }

    private double calculateCostForUKShipping(ShippingMethod shippingMethod) {
        switch (shippingMethod) {
            case STANDARD:
                return 8.0;
            case EXPRESS:
                return 14.0;
            default:
                throw new IllegalArgumentException("Invalid shipping method: " + shippingMethod);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

To test the private method calculateCost with switch cases, we can use the spy() method and Mockito.doCallRealMethod():

import org.mockito.Mockito;

public class ShippingServiceTest {

    @Test
    public void testCalculateCost() throws Exception {
        // Create a spy object of the ShippingService class
        ShippingService shippingService = Mockito.spy(new ShippingService());

        // Call the private method directly using Mockito.doCallRealMethod()
        double cost = Mockito.doCallRealMethod()
                .when(shippingService)
                .calculateCost(Mockito.anyString(), Mockito.any(ShippingMethod.class));

        // Assert the cost value for different destination countries and shipping methods
        assertEquals(5.0, shippingService.calculateCost("USA", ShippingMethod.STANDARD), 0.01);
        assertEquals(10.0, shippingService.calculateCost("USA", ShippingMethod.EXPRESS), 0.01);

        assertEquals(7.0, shippingService.calculateCost("Canada", ShippingMethod.STANDARD), 0.01);
        assertEquals(12.0, shippingService.calculateCost("Canada", ShippingMethod.EXPRESS), 0.01);

        assertEquals(8.0, shippingService.calculateCost("UK", ShippingMethod.STANDARD), 0.01);
        assertEquals(14.0, shippingService.calculateCost("UK", ShippingMethod.EXPRESS), 0.01);
    }
}
Enter fullscreen mode Exit fullscreen mode

In this example:

  • We create a spy object of the ShippingService class using Mockito.spy(new ShippingService()).
  • We use Mockito.doCallRealMethod() to instruct Mockito to call the real

implementation of the private method when it's invoked.

  • We assert the cost value returned by the calculateCost() method for different destination countries and shipping methods.

By using spy() and doCallRealMethod(), we create a spy object of the class under test and allow the private method to be executed with its real implementation. This way, we can test the overall behavior of the public method while indirectly testing the private methods with switch cases.

Remember to focus on testing the behavior of public methods that rely on the private logic rather than testing private methods directly. This approach ensures that the desired behavior is tested through the public interface of your classes.

Certainly! Here are some additional test cases you can add to the ShippingServiceTest class for the calculateCost method:

@Test
public void testCalculateCost_InvalidDestinationCountry() {
    // Arrange
    ShippingService shippingService = Mockito.spy(new ShippingService());
    String invalidCountry = "InvalidCountry";
    ShippingMethod shippingMethod = ShippingMethod.STANDARD;

    // Act and Assert
    assertThrows(IllegalArgumentException.class, () -> shippingService.calculateCost(invalidCountry, shippingMethod));
    Mockito.verify(shippingService).calculateCost(invalidCountry, shippingMethod);
}

@Test
public void testCalculateCost_InvalidShippingMethod() {
    // Arrange
    ShippingService shippingService = Mockito.spy(new ShippingService());
    String destinationCountry = "USA";
    ShippingMethod invalidMethod = null;

    // Act and Assert
    assertThrows(IllegalArgumentException.class, () -> shippingService.calculateCost(destinationCountry, invalidMethod));
    Mockito.verify(shippingService).calculateCost(destinationCountry, invalidMethod);
}

@Test
public void testCalculateShippingCost() {
    // Arrange
    ShippingService shippingService = Mockito.spy(new ShippingService());
    String destinationCountry = "USA";
    ShippingMethod shippingMethod = ShippingMethod.EXPRESS;
    double weight = 2.5;

    // Act
    double cost = shippingService.calculateShippingCost(destinationCountry, shippingMethod, weight);

    // Assert
    assertEquals(25.0, cost, 0.01);
    Mockito.verify(shippingService).calculateCost(destinationCountry, shippingMethod);
}
Enter fullscreen mode Exit fullscreen mode

In the testCalculateCost_InvalidDestinationCountry test case, we verify that an IllegalArgumentException is thrown when an invalid destination country is provided. Similarly, in the testCalculateCost_InvalidShippingMethod test case, we check that an IllegalArgumentException is thrown when an invalid shipping method is passed.

The testCalculateShippingCost test case verifies the overall behavior of the calculateShippingCost method by asserting the calculated cost for a specific destination country, shipping method, and weight.

These additional test cases provide coverage for exceptional scenarios and ensure that the private method is being called with the correct parameters.

Remember to update the test class annotations accordingly to include the new test methods.

Certainly! Here are a few more test cases you can add to the ShippingServiceTest class for the calculateShippingCost method:

@Test
public void testCalculateShippingCost_ZeroWeight() {
    // Arrange
    ShippingService shippingService = Mockito.spy(new ShippingService());
    String destinationCountry = "USA";
    ShippingMethod shippingMethod = ShippingMethod.STANDARD;
    double weight = 0.0;

    // Act
    double cost = shippingService.calculateShippingCost(destinationCountry, shippingMethod, weight);

    // Assert
    assertEquals(0.0, cost, 0.01);
    Mockito.verify(shippingService).calculateCost(destinationCountry, shippingMethod);
}

@Test
public void testCalculateShippingCost_NegativeWeight() {
    // Arrange
    ShippingService shippingService = Mockito.spy(new ShippingService());
    String destinationCountry = "USA";
    ShippingMethod shippingMethod = ShippingMethod.EXPRESS;
    double weight = -2.5;

    // Act
    double cost = shippingService.calculateShippingCost(destinationCountry, shippingMethod, weight);

    // Assert
    assertEquals(-25.0, cost, 0.01); // Negative cost due to negative weight
    Mockito.verify(shippingService).calculateCost(destinationCountry, shippingMethod);
}

@Test
public void testCalculateShippingCost_RoundCost() {
    // Arrange
    ShippingService shippingService = Mockito.spy(new ShippingService());
    String destinationCountry = "Canada";
    ShippingMethod shippingMethod = ShippingMethod.STANDARD;
    double weight = 3.8;

    // Act
    double cost = shippingService.calculateShippingCost(destinationCountry, shippingMethod, weight);

    // Assert
    assertEquals(26.6, cost, 0.01); // Rounded cost for weight = 3.8 and cost = 7.0
    Mockito.verify(shippingService).calculateCost(destinationCountry, shippingMethod);
}
Enter fullscreen mode Exit fullscreen mode

In the testCalculateShippingCost_ZeroWeight test case, we check that the cost is correctly calculated as zero when the weight is zero.

The testCalculateShippingCost_NegativeWeight test case ensures that the cost can be calculated correctly even when the weight is negative. It may result in a negative cost due to the negative weight value.

The testCalculateShippingCost_RoundCost test case verifies that the cost is rounded to two decimal places for weights that result in non-integer costs. It checks the rounding behavior of the shipping cost.

These additional test cases cover different scenarios such as zero weight, negative weight, and rounding of costs, ensuring that the calculateShippingCost method handles such cases correctly.

Remember to update the test class annotations accordingly to include the new test methods.

Bonus

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

public class MyTestClass {

private MyService myService;

@BeforeAll
public void setup() {
    // Perform common setup for all test methods
    myService = new MyService();
}

@Test
public void testMethodA() {
    // Arrange
    MyService spyService = Mockito.spy(myService);

    // Perform specific setup for testMethodA
    Mockito.when(spyService.someMethod()).thenReturn("Mocked Value");

    // Act and Assert
    // ... Test logic for testMethodA
}

@Test
public void testMethodB() {
    // Arrange
    MyService spyService = Mockito.spy(myService);

    // Perform specific setup for testMethodB
    // ... Example: Mockito.when(spyService.someOtherMethod()).thenReturn("Mocked Value");

    // Act and Assert
    // ... Test logic for testMethodB
}
Enter fullscreen mode Exit fullscreen mode

}

Top comments (0)