0

I am using micronaut framework and spock for writing test case of API. I am trying to create testcase of my API which internally calls PaymentIntent.retrieve() static method of 3rd party api. I want to mock this 3rd party url call and return a fakeObject of PaymentIntent instead.

Here is a sample test case that I created which is executing the actual 3rd party api static method:

@Inject Service myService;

@Unroll
void "method returns nothing"() {
  given:
  PaymentIntent paymentIntent = new PaymentIntent()
  Mock(PaymentIntent)
  PaymentIntent.retrieve("pi_123", requestOptions) >> paymentIntent
  
  when:
  def result = myService.getPayment("", "pi_123", obj)

  then:
  result.amount == paymentIntent.amount
}

Can someone guide me around how can restrict the execution of the actual API?

I have refer these already asked questions but it is not worked in my case. Mock static method with GroovyMock or similar in Spock

Dmytro Maslenko
  • 2,247
  • 9
  • 16
  • Welcome to SO. Please be advised learn what an [MCVE](https://stackoverflow.com/help/mcve) is and how it helps you to get the answers you need. A test snippet, not even being a full class, in combination with the fact that you did not provide the class under test makes it hard to answer your question, which is why Jeff in his answer had to speculate. This assumption that your class under test is written in Groovy might be true or false, on which depends if his answer shall work for you or not. – kriegaex Jan 06 '21 at 00:35

2 Answers2

0

The solution will depend on what language the class calling PaymentIntent.retrieve is written in. The following assumes Groovy because the question is tagged with groovy.

import com.stripe.exception.StripeException
import com.stripe.model.PaymentIntent
import com.stripe.net.RequestOptions

import javax.inject.Singleton

@Singleton
class MyService {
    PaymentIntent getPayment(String s1, String s2, RequestOptions options) throws StripeException {
        PaymentIntent.retrieve s1, options
    }
}
import com.stripe.model.PaymentIntent
import io.micronaut.test.extensions.spock.annotation.MicronautTest
import spock.lang.Specification

import javax.inject.Inject

@MicronautTest
class MyServiceSpec extends Specification {
    @Inject
    MyService myService;

    void "method returns nothing"() {
        when:
        PaymentIntent paymentIntent = new PaymentIntent()
        paymentIntent.amount = 42
        GroovySpy(PaymentIntent, global: true)
        1 * PaymentIntent.retrieve("pi_123", _) >> paymentIntent

        def result = myService.getPayment("pi_123", null, null)

        then:
        result.amount == 42
    }
}
Jeff Scott Brown
  • 26,804
  • 2
  • 30
  • 47
0

It is not trivial thing to mock static stuff. I would recommend to extract the 3rd party call into a separate method which can be overridden in the unit test.

Assume your Service.getPayment() looks like

  class MyService {
    PaymentIntent getPayment(String s1, String s2, RequestOptions options) throws StripeException {
        // some logic here
        // ...

        PaymentIntent.retrieve s1, options
    }
  }

Let refactor it

  class MyService {
    PaymentIntent getPayment(String s1, String s2, RequestOptions options) throws StripeException {
        // some logic here
        // ...

        doRetrieveCall s1, options
    }

    PaymentIntent doRetrieveCall(String s1, RequestOptions options) throws StripeException {
        PaymentIntent.retrieve s1, options
    }
  }

Your unit test

  given:
    def myService = new Service() {
      // overriden
      PaymentIntent doRetrieveCall(String s1, RequestOptions options) throws StripeException {
        // todo validate of the s1 for "pi_123"
        // todo validate of the options

        // return a fake instance
        new PaymentIntent()
      }
    }
  
  when:
    def result = myService.getPayment("", "pi_123", obj)

  then:
    result.amount == paymentIntent.amount
Dmytro Maslenko
  • 2,247
  • 9
  • 16