it-swarm.com.ru

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

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 . Есть ли идея сделать тестовый пример намного проще?

48
jilen

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 отмечают, что это следует использовать только для устаревшего кода. В противном случае лучше вставить Push-код в ваш CacheContext и предоставить любую информацию, необходимую для выполнения самой работы. Объем информации, которую вы извлекаете из CacheContext, говорит о том, что у вашего класса есть особая зависть .

111
Lunivore

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

https://github.com/ko5tik/andject/blob/master/src/test/Java/de/pribluda/Android/andject/ViewInjectionTest.Java

Здесь я высмеиваю базовый класс Activity, который идет от 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
Konstantin Pribluda

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

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

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

3
Doug R

На всякий случай, если вы используете 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)
0
yuranos87