Mockito example
Published: 2023-06-13 13:05:46

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

```java
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);
        }
    }
}
```

And here's the corresponding test using Mockito:

```java
@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
}
```

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.

```java
@RunWith(MockitoJUnitRunner.class)
public class DiscountServiceTest {

    private DiscountService discountService;

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

    // Rest of the test methods...
}
```

2. Mock the Private Method Behavior:
   - Use `Mockito.doReturn()` to define the behavior of the private method when called with specific arguments.

```java
@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);
}
```

3. 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.

```java
// ...

@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);
}

// ...
```

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.

```java
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;
    }
}
```

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

```java
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);
    }
}
```

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.

```java
PaymentService paymentService = Mockito.spy(new PaymentService());
```

2. 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.

```java
Mockito.doCallRealMethod()
       .when(paymentService)
       .calculateFee(Mockito.any(PaymentMethod.class));
```

3. 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.

```java
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);
```

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.

```java
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);
        }
    }
}
```

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

```java
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);
    }
}
```

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:

```java
@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);
}
```

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:

```java
@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);
}
```

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
    }
}