Можно ли заставить Расширение JUnit5 реализовать интерфейс, который выполняется расширенным классом? - PullRequest
0 голосов
/ 30 октября 2019

Я хотел бы написать Расширение JUnit5 , которое расширяет мой тестовый класс,

@ExtendWith(MyExtension.class)
public class MyTestClass {

  @Test myTest1() {}

  @Test myTest2() {}

  // ...
}

Однако мой тестовый класс также реализует определенный интерфейс, поэтому он выглядит примерно так:

public interface SomeInterface {
  SomeClient getSomeClient();
  SomeClient getSomeClientAsAdministrator();
}

@ExtendWith(MyExtension.class)
public class MyTestClass implements SomeInterface {

  @Test myTest1() {}

  @Test myTest2() {}

  // ...

  SomeClient getSomeClient() {
    // ...
  }

  SomeClient getSomeClientAsAdministrator() {
    // ...
  }
}

Пока никаких загадок.

Но теперь я хочу, чтобы эти реализации интерфейса были также доступны для расширения, например,

public class MyExtension implements BeforeEachCallback, SomeInterface
{

  @Override
  public void beforeAll(ExtensionContext extensionContext) {
    // be able to use getSomeClient();
  }
}

Как я могу настроить свои классы для достижения этой цели? (Или какой врожденный недостаток или запах кода препятствует этому?)

Ответы [ 2 ]

1 голос
/ 31 октября 2019

Один из способов добиться этого - использовать getTestInstance() для объекта контекста:

public class MyExtension implements BeforeEachCallback {
    @Override
    public void beforeEach(ExtensionContext context) throws Exception {

        context.getTestInstance().ifPresent(instance -> {
            if (instance instanceof SomeInterface) {
                SomeInterface some = (SomeInterface) instance;
                System.out.println(some.getSomeClient());
            }
        });
    }
}

Здесь вы можете увидеть две вещи:

  1. Возможно, необъект экземпляра теста, например, в BeforeAllCallback, поскольку тестовые экземпляры обычно создаются для каждого теста.
  2. Требуется приведение. Это означает, что вы должны проверить, действительно ли ваш тестовый экземпляр реализует SomeInterface

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

1 голос
/ 31 октября 2019

Вам необходимо использовать аннотацию @RegisterExtension, которая позволяет создавать экземпляр расширения вручную.

Когда расширение регистрируется декларативно через @ExtendWith, оно обычно можетнастраиваться только с помощью аннотаций. Напротив, когда расширение зарегистрировано через @RegisterExtension, оно может быть настроено программно - например, для передачи аргументов в конструктор расширения, статический метод фабрики или API построителя.

Звучит так, как будто SomeClient предоставлен откуда-то еще (например, DI вроде Spring), но он вам нужен в MyExtension. Предполагая этот сценарий, вы можете начать с чего-то вроде:

@ExtendWith(SpringExtension.class)
public class MyTestClass {
  @Autowired SomeClient someClient;
  @RegisterExtension
  MyExtension myExtension = new MyExtension(someClient);
}
...