Подтвердить что ты не робот

Макет или заглушка для прикованного вызова

protected int parseExpire(CacheContext ctx) throws AttributeDefineException {
    Method targetMethod = ctx.getTargetMethod();
    CacheEnable cacheEnable = targetMethod.getAnnotation(CacheEnable.class);
    ExpireExpr cacheExpire = targetMethod.getAnnotation(ExpireExpr.class);
    // check for duplicate setting
    if (cacheEnable.expire() != CacheAttribute.DO_NOT_EXPIRE && cacheExpire != null) {
        throw new AttributeDefineException("expire are defined both in @CacheEnable and @ExpireExpr");
    }
    // expire time defined in @CacheEnable or @ExpireExpr
    return cacheEnable.expire() != CacheAttribute.DO_NOT_EXPIRE ? cacheEnable.expire() : parseExpireExpr(cacheExpire, ctx.getArgument());
}

который является методом тестирования,

Method targetMethod = ctx.getTargetMethod();
CacheEnable cacheEnable = targetMethod.getAnnotation(CacheEnable.class);

Я должен издеваться над тремя CacheContext, Method и CacheEnable. Есть ли идея сделать тест более простым?

4b9b3361

Ответ 1

Mockito может работать с цепными заглушками:

Foo mock = mock(Foo.class, RETURNS_DEEP_STUBS);

// note that we're stubbing a chain of methods here: getBar().getName()
when(mock.getBar().getName()).thenReturn("deep");

// note that we're chaining method calls: getBar().getName()
assertEquals("deep", mock.getBar().getName());

AFAIK, первый метод в цепочке возвращает макет, который настроен на возврат вашего значения при втором вызове метода.

Авторы Mockito отмечают, что это следует использовать только для устаревшего кода. В противном случае лучше вставить это поведение в ваш CacheContext и предоставить любую информацию, необходимую для выполнения самой работы. Объем информации, которую вы извлекаете из CacheContext, говорит о том, что у вашего класса есть зависть к функциям.

Ответ 2

Я обнаружил, что JMockit проще использовать и полностью переключился на него. См. Примеры использования:

https://github.com/ko5tik/andject/blob/master/src/test/java/de/pribluda/android/andject/ViewInjectionTest.java

Здесь я высмеиваю активный класс активности, который исходит от Android SKD и полностью погасил. С JMockit вы можете издеваться над предметами, которые являются окончательными, частными, абстрактными или что-то еще.

В вашей тестовой форме это будет выглядеть так:

public void testFoo(@Mocked final Method targetMethod, 
                    @Mocked  final CacheContext context,
                    @Mocked final  CacheExpire ce) {
    new Expectations() {
       {
           // specify expected sequence of infocations here

           context.getTargetMethod(); returns(method);
       }
    };

    // call your method
    assertSomething(objectUndertest.cacheExpire(context))

Ответ 3

Мое предложение упростить ваш тестовый пример - реорганизовать ваш метод.

В любое время, когда у меня возникают проблемы с тестированием метода, это запах кода для меня, и я спрашиваю, почему это трудно проверить. И если код трудно тестировать, его, вероятно, трудно использовать и поддерживать.

В этом случае это потому, что у вас есть цепочка методов, которая имеет несколько уровней в глубину. Возможно, перейдите в ctx, cacheEnable и cacheExpire в качестве параметров.

Ответ 4

На всякий случай, если вы используете Kotlin. MockK ничего не говорит о цепочке, являющейся плохой практикой, и легко позволяет вам сделать это.

val car = mockk<Car>()

every { car.door(DoorType.FRONT_LEFT).windowState() } returns WindowState.UP

car.door(DoorType.FRONT_LEFT) // returns chained mock for Door
car.door(DoorType.FRONT_LEFT).windowState() // returns WindowState.UP

verify { car.door(DoorType.FRONT_LEFT).windowState() }

confirmVerified(car)