Проверка вызова защищенного супер метода


У меня есть следующая структура:

class Bar{
  ....
  protected void restore(){
    ....
  }

  ....
}

Этот класс расширяется на Foo, как показано ниже:

class Foo extends Bar{
    ....

    @Override
    public void restore(){  //valid override
        super.restore();

        ....
    }
}

В моем тесте jUnit я хотел бы проверить, что когда foo.restore() вызывается, то super.restore() вызывается впоследствии. Следовательно, ниже приведен мой метод теста jUnit:

class FooTest{
  @Tested
  Foo _foo;

  @Test
  void testRestore(final Bar bar){

    new Expectations(){{
      bar.restore(); times = 1; // Error! bar.restore() not visible
    }};

    Deencapsulation.invoke(_foo,"restore");
  }
}

К сожалению, мой тест не может компилироваться. Причина в том, что 1) restore() родителя является protected и 2) FooTest и Foo существуют вместе в отдельном проекте (и, следовательно, папке) против Bar.

Есть ли вообще чтобы добиться желаемого теста? Я проверил jmockit tutorials (много раз за последние несколько месяцев) и не видел подобного теста (то же самое касается поиска в Google).


Обновить

С помощью ответов я понимаю, что принуждение подклассов к вызову super не является лучшей практикой, но это не моя реализация, и я все еще должен проверить ее. Я все еще ищу способ применить мой тест jUnit, чтобы проверить, если вызов к родителю происходит.

3 5

3 ответа:

Должен сработать следующий тест:

public class FooTest
{
    @Tested Foo _foo;

    @Test
    void restoreInFooCallsSuper(@Mocked final Bar bar)
    {
        new Expectations() {{
            invoke(bar, "restore");
        }};

        _foo.restore();
    }
}

Таким образом, в основном вы пытаетесь навязать контракт вызова супер и пытаетесь разрешить подклассы? Я думаю, что это нелегко сделать из-за динамической диспетчеризации, которая скроет поведение в Java. Я не думаю, что насмешка поймает это.

Способ гарантировать, что супер вызывается, состоял бы в том, чтобы разбить супер и расширение на 2 метода, таких как

class Foo {
  public final void restore() {
    //parent code...
    doRestore();
  }

  protected void doRestore() {
    //empty base implementation
  }
}

class Bar extends Foo {
    protected void doRestore() {
      //do my subclass specific restore stuff here
    } 
}

Предполагается, что super.restore() должен делать что-то полезное нет? какая-то особая логика. В вашем тесте просто проверьте, что результат вызова super.restore() произошел.

Еще один способ заглянуть в него заключается в следующем. В подклассе перед выполнением чего-либо вы реализуете assert, который гарантирует, что супер сделал свою работу правильно. Это более сильная проверка и хорошо известна как часть Мейера. проектирование по контракту парадигма. В этом контексте подкласс просто проверяет, что постусловие реализации super.restore() выполняется перед выполнением и с помощью assert Вы знаете, что она не будет работать во время модульных тестов, но также и во время тестовых интеграционных запусков вашего приложения, например

class Foo extends Bar{
    ....

    @Override
    public void restore(){  //valid override
        super.restore();
        assert super_restore_worked_ok_condition : "restore post-condition failed";

        ....
    }
}