junit Java mockito测试静态方法在运行中保留来自第一个测试用例的mock

qnzebej0  于 5个月前  发布在  Java
关注(0)|答案(1)|浏览(59)

我试图创建多个测试用例与Mockito在Java中的静态模拟。他们运行时,单独的罚款,但当我运行整个测试类的模拟方法首先运行(在本例中,shouldrePricingIfSucceeding)也会影响其他测试用例(在这种情况下,shouldNotrePricingIfRequestFails永远不会失败).我现在已经试着把所有我嘲笑的东西放在他们自己的测试方法中,但即使这样也不起作用。下面是我的代码:

public class PricingService {
    public static final int PRODUCT_CODE = 10;
    private final ZoneId zoneId = ZoneId.of("UTC");
    private static final Logger LOGGER = LoggerFactory.getLogger(PricingService.class);
    private static final PricingOauthApi pricingOauthApi = PricingOauthApiFactory.create();
    private static final PricingApi pricingApi = PricingApiFactory.create();
    private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX");

    public boolean requiresPricingBeforeSendPush(PushCSCTransaction pushCSCTransaction) {
        int transactionType = pushCSCTransaction.getCscTransaction().getTransactionType();
        if (!pushCSCTransaction.getControlArea().getSource().equals("TEST") ||
            transactionType != 30 &&
                transactionType != 31)
            return false;

        boolean sendRequestSuccessfully = sendPriceRequest(pushCSCTransaction);

        return sendRequestSuccessfully && transactionType == 31;
    }

    private boolean sendPriceRequest(PushCSCTransaction pushCSCTransaction) {
        try {
            OauthRequest oauthRequest = new OauthRequest(Configuration.Pricing.getOauthScope(), Configuration.Pricing.getOauthClientId(), Configuration.Pricing.getOauthClientSecret());
            Response<OauthResponse> oauthResponse = pricingOauthApi.oauth(oauthRequest, Configuration.Pricing.getOauthPathId()).execute();

            if (!oauthResponse.isSuccessful() || oauthResponse.body() == null) throw new WebApplicationException("");

            Response<Void> response = pricingApi.pricing(pushCSCTransaction, "Bearer " + oauthResponse.body().getAccessToken()).execute();

            return response.isSuccessful();
        } catch (Exception exception) {
            LOGGER.error("Error when trying to send transaction message", exception);
            return false;
        }
    }
}

@ExtendWith(MockitoExtension.class)
public class PricingServiceTest {
    @Test
    public void shouldNotRequirePricingIfRequestFails() throws IOException {
        PricingApi pricingApi = mock();
        PricingOauthApi pricingOauthApi = mock();
        try (MockedStatic<PricingApiFactory> pricingApiFactory = Mockito.mockStatic(PricingApiFactory.class);
             MockedStatic<PricingOauthApiFactory> pricingOauthApiFactory = Mockito.mockStatic(PricingOauthApiFactory.class)) {
            pricingApiFactory.when(PricingApiFactory::create).thenReturn(pricingApi);
            pricingOauthApiFactory.when(PricingOauthApiFactory::create).thenReturn(pricingOauthApi);
            Call<OauthResponse> call = mock(Call.class);
            Mockito.when(pricingOauthApi.oauth(Mockito.any(), Mockito.any())).thenReturn(call);
            Mockito.when(call.execute()).thenThrow(new IOException("Test"));

            PushCSCTransaction transaction = createCsvTransaction("TEST", 31, PRODUCT_CODE, 1312, 311, 1);
            PricingService service = new PricingService();

            boolean result = service.requiresPricingBeforeSendPush(transaction);

            assertFalse(result);
            Mockito.verify(pricingOauthApi).oauth(Mockito.any(), Mockito.any());
            Mockito.verify(pricingApi, Mockito.never()).pricing(Mockito.any(), Mockito.any());
        }
    }

    @Test
    public void shouldRequirePricingIfSucceeding() throws IOException {
        PricingApi pricingApi = mock();
        PricingOauthApi pricingOauthApi = mock();
        try (MockedStatic<PricingApiFactory> pricingApiFactory = Mockito.mockStatic(PricingApiFactory.class);
             MockedStatic<PricingOauthApiFactory> pricingOauthApiFactory = Mockito.mockStatic(PricingOauthApiFactory.class)) {
            pricingApiFactory.when(PricingApiFactory::create).thenReturn(pricingApi);
            Call<Void> call = mock(Call.class);
            Mockito.when(pricingApi.pricing(Mockito.any(), Mockito.any())).thenReturn(call);
            Mockito.when(call.execute()).thenReturn(Response.success(null));

            pricingOauthApiFactory.when(PricingOauthApiFactory::create).thenReturn(pricingOauthApi);
            Call<OauthResponse> callOauth = mock(Call.class);
            Mockito.when(pricingOauthApi.oauth(Mockito.any(), Mockito.any())).thenReturn(callOauth);
            OauthResponse oauthResponse = new OauthResponse();
            Mockito.when(callOauth.execute()).thenReturn(Response.success(oauthResponse));

            PushCSCTransaction transaction = createCsvTransaction("TEST", 31, PRODUCT_CODE, 1312, 311, 1);
            PricingService service = new PricingService();

            boolean result = service.requiresPricingBeforeSendPush(transaction);

            assertTrue(result);
            Mockito.verify(pricingOauthApi).oauth(Mockito.any(), Mockito.any());
            Mockito.verify(pricingApi).pricing(Mockito.any(), Mockito.any());
        }
    }
}

字符串
所以当我运行这段代码时,我总是从sendPriceRequest得到一个true,因为mock永远不会改变以抛出异常。我忘记了取消mock静态方法吗?我使用的是Java 8和mockito版本4.11.0和junit 5。
还尝试添加:

@BeforeEach
    public void setUp() {
        Mockito.clearAllCaches();
    }


但这也不起作用。

vof42yt1

vof42yt11#

这个问题与mocking静态方法无关。您的mockStatic调用被正确地 Package 在try-with-resources块中。
问题出在使用静态字段的PricingService中。静态字段pricingOauthApipricingApi只初始化一次-当您创建服务的第一个示例时。
观察更简单的示例:

class FooCollaborator {
}

class FooService {
    static FooCollaborator fooCollaborator = createFoo();

    static FooCollaborator createFoo() {
        System.out.println("static createFoo called");
        return new FooCollaborator();
    }

}

public class StaticTest {
    @Test
    void test1() {
        System.out.println("test1");
        FooService fooService = new FooService();
        System.out.println(fooService.fooCollaborator);
    }

    @Test
    void test2() {
        System.out.println("test2");
        FooService fooService = new FooService();
        System.out.println(fooService.fooCollaborator);
    }
}

字符串
输出量:

test1
static createFoo called
com.so.examples.mockito.FooCollaborator@327514f

test2
com.so.examples.mockito.FooCollaborator@327514f

  • 静态字段仅初始化一次
  • 初始化发生在创建服务的第一个示例时(因此,您有机会存根您的静态方法)

典型的模式是不将服务的协作者保存在静态字段中。更好的是,将它们作为构造函数参数传递(作为一个额外的好处,您不需要在测试中模拟静态工厂方法)。

相关问题