Статьи

Выпущен AccuREST Stub Runner

Это было хорошее время выпуска недавно! Я пишу в блоге Too Much Coding больше о релизах, чем о конкретных темах;)

После выпуска Spring Cloud Sleuth в составе Brixton RC1 мы только что выпустили версию AccuREST 1.0.4. Мы исправили несколько ошибок, но ввели несколько важных функций, в том числе:

  • Поддержка плагинов Maven
  • Функциональность Stub Runner

Этот пост опишет последнюю функцию более подробно.

Вступление

Я довольно много говорил о библиотеке под названием Micro-Infra-Spring, где я представил, как можно извлечь выгоду из функциональности Stub Runner . С тех пор как я покинул компанию, владеющую этим хранилищем, проект практически не обслуживался. В течение достаточно долгого времени любая разработка была сделана главным образом мной, и фактически я был автором большей части кода Stub Runner . Из-за вышеупомянутого и того факта, что Stub Runner тесно связан с функцией создания заглушек AccuREST, я решил перенести ее в репозиторий AccuREST.

Точное резюме

Stub Runner тесно связан с концепциями AccuREST. Для получения дополнительной информации о AccuREST вы можете проверить мои записи в блоге или проверить проект AccuREST на Github . Если вы не знаете, что это такое, я постараюсь сделать очень быстрое резюме.

AccuREST — это верификатор Consumer Driven Contracts, в котором вы определяете контракт вашего API через Groovy DSL. Из этого DSL на стороне сервера создаются тесты, чтобы проверить, говорит ли ваш контракт правду. С точки зрения Stub Runner более интересной является сторона клиента. Для клиентской стороны AccuREST генерирует заглушки WireMock из предоставленного DSL, чтобы клиентам этого API можно было предоставить надежные заглушки.

Что такое огрызок?

Теперь, когда мы помним, что делает AccuREST, мы можем более подробно взглянуть на Stub Runner . Давайте предположим, что у нас есть следующий поток услуг (кстати, это скриншот Zipkin, интегрированного с Spring Cloud Sleuth )

dependencies_accurest

Давайте представим себя разработчиками сервиса2, который называет сервис3 и сервис4 . Поскольку мы используем подход CDC ( Consumer Driven Contracts ), давайте предположим, что заглушки service3 и service4 уже развернуты в некотором репозитории Maven.

Если я пишу интеграционные тесты service2, у меня наверняка будут некоторые точки взаимодействия с service3 и service4 . Скорее всего, в большинстве случаев я просто высмеиваю эти взаимодействия в своем коде, но было бы полезно сделать реальный HTTP-вызов для другого приложения. Конечно, я не хочу загружать оба сервиса и запускать их только для интеграционных тестов — это было бы излишним. Вот почему наиболее предпочтительным решением на этом этапе будет запускать заглушки моих сотрудников.

Поскольку мне лень что-то делать вручную, я бы предпочел, чтобы заглушки автоматически загружались для меня, серверы WireMock запускались и получали определения заглушек.

И это именно то, что Stub Runner может сделать для вас!

Как это работает?

концепция

По своей сути Stub Runner использует механизм Groovy Grape для загрузки заглушек из заданного репозитория Maven. Затем он распаковывает их во временную папку. Предположим, у вас есть следующая структура ваших заглушек WireMock внутри JAR-заглушки (пример для service3-stubs.jar )

1
2
3
4
5
6
7
├── META-INF
│   └── MANIFEST.MF
└── mappings
    └── service3
        ├── shouldMarkClientAsFraud.json
        ├── notAWireMockMapping.json
        └── shouldSayHello.json

Stub Runner просканирует весь распакованный JAR- .json на .json файлов .json . Существует соглашение, что определения заглушек помещаются в папку mappings . Поэтому он выберет shouldMarkClientAsFraud.json , notAWireMockMapping.json и shouldSayHello.json .

Затем для каждой зависимости запускается экземпляр WireMock, и каждый найденный JSON пытается проанализировать как определение заглушки WireMock. Любые исключения в этой точке игнорируются (при условии, что notAWireMockMapping.json не является допустимым определением WireMock, исключение будет подавлено). В нашем сценарии будут запущены 2 сервера WireMock — один для service3 и один для service4 .

Таким образом, вам не нужно копировать заглушки вручную. Заглушки централизованы, так как они хранятся в репозитории Maven. Это чрезвычайно важно, потому что Stub Runner всегда загружает самую новую версию заглушек, поэтому вы можете быть уверены, что ваши тесты прервутся, как только кто-нибудь внесет несовместимые изменения.

API

С точки зрения разработчика, есть только несколько классов Stub Runner, которые следует использовать. В большинстве случаев вы будете использовать следующие:

StubFinder

Интерфейс, который позволяет вам найти URL запущенного экземпляра WireMock. Вы можете найти этот URL, передав нотацию Ivy ( groupId:artifactId ) или просто artifactIdStub Runner попытается позаботиться об остальном.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
interface StubFinder {
  /**
   * For the given groupId and artifactId tries to find the matching
   * URL of the running stub.
   *
   * @param groupId - might be null. In that case a search only via artifactId takes place
   * @return URL of a running stub or null if not found
   */
  URL findStubUrl(String groupId, String artifactId)
 
  /**
   * For the given Ivy notation {@code groupId:artifactId} tries to find the matching
   * URL of the running stub. You can also pass only {@code artifactId}.
   *
   * @param ivyNotation - Ivy representation of the Maven artifact
   * @return URL of a running stub or null if not found
   */
  URL findStubUrl(String ivyNotation)
 
  /**
   * Returns all running stubs
   */
  RunningStubs findAllRunningStubs()
}

RunningStubs

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

running_stubs

StubRunning

Контракт для классов, которые могут запускать заглушки:

1
2
3
4
5
6
7
interface StubRunning extends Closeable, StubFinder {
  /**
   * Runs the stubs and returns the {@link RunningStubs}
   */
  RunningStubs runStubs()
 
}

StubRunner

Представляет один экземпляр готовых к работе заглушек. Он может запустить заглушки и вернет запущенный экземпляр WireMock, завернутый в класс RunningStubs . Поскольку он реализует StubFinder его также можно запросить, если текущий groupid и artifactid соответствуют соответствующей запущенной заглушке.

BatchStubRunner

Если у вас есть несколько служб, для которых вы хотите запустить WireMocks с заглушками, достаточно использовать BatchStubRunner . Он перебирает данный Iterable из StubRunner и выполняет логику для каждого из них.

Бегущий огрызок

Во всех приведенных ниже примерах предположим, что заглушки хранятся в репозитории Maven, доступном по адресу http://toomuchcoding.com . В качестве service2 я хотел бы загрузить заглушки com.toomuchcoding:service3 и com.toomuchcoding:service4 services.

Заглушка как толстый баночка

Как это использовать?

Stub Runner поставляется с основным классом ( io.codearte.accurest.stubrunner.StubRunnerMain ), который можно запускать со следующими параметрами:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
-maxp (--maxPort) N            : Maximum port value to be assigned to the
                                  Wiremock instance. Defaults to 15000
                                  (default: 15000)
 -minp (--minPort) N            : Minimal port value to be assigned to the
                                  Wiremock instance. Defaults to 10000
                                  (default: 10000)
 -s (--stubs) VAL               : Comma separated list of Ivy representation of
                                  jars with stubs. Eg. groupid:artifactid1,group
                                  id2:artifactid2:classifier
 -sr (--stubRepositoryRoot) VAL : Location of a Jar containing server where you
                                  keep your stubs (e.g. http://nexus.net/content
                                  /repositories/repository)
 -ss (--stubsSuffix) VAL        : Suffix for the jar containing stubs (e.g.
                                  'stubs' if the stub jar would have a 'stubs'
                                  classifier for stubs: foobar-stubs ).
                                  Defaults to 'stubs' (default: stubs)
 -wo (--workOffline)            : Switch to work offline. Defaults to 'false'
                                  (default: false)

Вы можете запустить этот основной класс из IDE или создать себе толстый JAR. Для этого достаточно вызвать следующую команду:

1
./gradlew stub-runner-root:stub-runner:shadowJar -PfatJar

Затем внутри build/lib будет толстый JAR с классификатором fatJar ожидающим вашего выполнения.

Возвращаясь к нашему примеру после создания толстого JAR- файла, я бы просто вызвал следующую команду, чтобы получить заглушки service3 и service4 из репозитория Maven, доступного по адресу http://toomuchcoding.com .

1
java -jar stub-runner-1.0.4-SNAPSHOT-fatJar.jar -sr http://toomuchcoding.com -s com.toomuchcoding:service3:stubs,com.toomuchcoding.service4

Когда это использовать?

Запуск Stub Runner в качестве основного класса наиболее целесообразен, когда вы запускаете быстрые дымовые тесты для развернутого приложения, где вы не хотите загружать и запускать всех сотрудников этого приложения. Для более разумного обоснования такого подхода вы можете проверить мою статью о развертывании Microservice

Заглушка Бегун Юнит Правило

Как это использовать?

Вы можете использовать правило JUnit для Stub Runner, чтобы автоматически загружать и запускать заглушки во время ваших тестов. AccurestRule реализует интерфейс StubFinder поэтому вы можете легко найти URL-адреса интересующих вас сервисов.

Вот как вы могли бы сделать это со Споком:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
class SomeSpec extends Specification {
 
  @ClassRule @Shared AccurestRule rule = new AccurestRule()
      .repoRoot('http://toomuchcoding.com')
      .downloadStub("com.toomuchcoding", "service3")
      .downloadStub("com.toomuchcoding:service4")
 
  def 'should do something useful when service3 is called'() {
        given:
            URL service3Url = rule.findStubUrl('com.toomuchcoding', 'service3')
        expect:
            somethingUseful(service3Url)
    }
 
  def 'should do something even more useful when service4 is called'() {
        given:
            URL service4Url = rule.findStubUrl('service4')
        expect:
            somethingMoreUseful(service4Url)
    }
}

или с простым Java JUnit:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
public class SomeTest {
 
  @ClassRule public static AccurestRule rule = new AccurestRule()
      .repoRoot("http://toomuchcoding.com")
      .downloadStub("com.toomuchcoding", "service3")
      .downloadStub("com.toomuchcoding:service4");
 
  @Test
  public void should_do_something_useful_when_service3_is_called() {
        URL service3Url = rule.findStubUrl("com.toomuchcoding", "service3");
 
        somethingUseful(service3Url);
  }
 
  @Test
  public void should_do_something_even_more_useful_when_service4_is_called() {
        URL service4Url = rule.findStubUrl("service4");
 
        somethingMoreUseful(service4Url);
  }
}

Когда это использовать?

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

Заглушка бегун весна

Как это использовать?

Вы можете использовать конфигурацию Spring для Stub Runner, чтобы загрузить заглушки ваших соавторов и запустить сервер WireMock при загрузке контекста Spring. Мы предоставляем StubRunnerConfiguration которую вы можете импортировать в свои тесты. В этой конфигурации мы регистрируем боб StubFinder который вы можете автоматически подключать в своих тестах.

Имея следующий файл application.yaml :

1
2
stubrunner.stubs.repository.root: http://toomuchcoding.com
stubrunner.stubs.ids: com.toomuchcoding:service3:stubs,com.toomuchcoding.service4

Вот как ты мог сделать это со Споком

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@ContextConfiguration(classes = Config, loader = SpringApplicationContextLoader)
class StubRunnerConfigurationSpec extends Specification {
 
  @Autowired StubFinder stubFinder
 
  def 'should do something useful when service3 is called'() {
      given:
          URL service3Url = stubFinder.findStubUrl('com.toomuchcoding', 'service3')
      expect:
          somethingUseful(service3Url)
  }
 
  def 'should do something even more useful when service4 is called'() {
      given:
          URL service4Url = stubFinder.findStubUrl('service4')
      expect:
          somethingMoreUseful(service4Url)
  }
 
  @Configuration
  @Import(StubRunnerConfiguration)
  @EnableAutoConfiguration
  static class Config {}
 
}

Когда это использовать?

В ваших тестах, если у вас есть Spring и у вас нет Spring Cloud. Также вы можете добавить его во время компиляции (разумеется, вам придется добавить несколько профилей Spring, чтобы не запускать его на производстве), чтобы получить прибыль от режима «разработки» запуска микросервисов. Это означает, что если вы загрузите свое приложение, чтобы щелкнуть по нему — все заглушки вокруг вас уже будут загружены и запущены.

Stub Runner Весеннее Облако

Как это использовать?

Вы можете использовать конфигурацию Spring Cloud для Stub Runner, чтобы получать выгоду от заштрихованных соавторов при использовании абстракций Spring Cloud над обнаружением служб и при использовании ленты Netflix. Конфигурация Stub Runner Spring Cloud является AutoConfiguration поэтому она автоматически запускается для вас.

Предположим, что вы ссылаетесь на service3 как на service3 в своем коде, а на service4 — на shouldMapThisNameToService4 . Это означает, что вы используете, например, @LoadBalanced RestTemplate следующим образом (не используйте инъекцию полей, как я делаю в этом примере !!):

01
02
03
04
05
06
07
08
09
10
11
12
13
@Component
class SomeClass {
 
  @Autowired @LoadBalanced RestTemplate restTemplate
 
  void doSth() {
    // code...
    String service3Response = restTemplate.getForObject('http://service3/name', String)
    String service4Response = restTemplate.getForObject('http://shouldMapThisNameToService4/name', String)
    // more code...
  }
 
}

Если идентификатор службы, который вы используете для вызова других служб, отображается точно на имя идентификатора артефакта в репозитории Maven, то вам повезло, и вам не нужно ничего делать, чтобы найти работающие заглушки. Однако если это не так — не волнуйтесь, вам просто нужно сопоставить это самостоятельно.

Свойство stubrunner.stubs.idsToServiceIds является корневым путем к карте, в которой ключ является идентификатором артефакта загруженной заглушки, а значениеидентификатором службы, используемым в коде.

Имея следующий файл application.yaml :

1
2
3
4
5
stubrunner.stubs.repository.root: http://toomuchcoding.com
stubrunner.stubs.ids: com.toomuchcoding:service3:stubs,com.toomuchcoding.service4
 
stubrunner.stubs.idsToServiceIds:
  service4: shouldMapThisNameToService4

Вот как ты мог сделать это со Споком

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
@ContextConfiguration(classes = Config, loader = SpringApplicationContextLoader)
class StubRunnerConfigurationSpec extends Specification {
 
  @Autowired SomeClass someClass
 
  def 'should not explode'() {
      when:
          someClass.doSth()
      expect:
          noExceptionThrown()
  }
 
  @Configuration
  @EnableAutoConfiguration
  static class Config {}
 
}

Когда это использовать?

Когда вы используете Spring Cloud. Вы можете получить прибыль от Stub Runner Spring Cloud также в режиме «разработчика», как представлено в разделе « Stub Runner Spring ».

Дополнительные параметры конфигурации

Вы можете установить значение по умолчанию для репозитория Maven с помощью системного свойства:

1
-Dstubrunner.stubs.repository.root=http://your.maven.repo.com

Список настраиваемых свойств содержит:

название Значение по умолчанию Описание
stubrunner.port.range.min 10000 Минимальное значение порта для сервера WireMock
stubrunner.port.range.max 15000 Максимальное значение порта для сервера WireMock
stubrunner.stubs.repository.root Адрес вашего репо М2 (будет указывать на локальный репо М2, если ничего не указано)
stubrunner.stubs.classifier заглушки Классификатор по умолчанию для JAR-файлов, содержащих заглушки
stubrunner.work-форум ложный Следует попробовать подключиться к любому репо, чтобы загрузить заглушки (полезно, если нет интернета)
stubrunner.stubs Список заглушек по умолчанию, разделенных запятой

Резюме

Заглушка Бегун :

  • Уже зарекомендовал себя как очень полезный инструмент при выполнении CDC.
  • Был испытан в бою, и все больше компаний заявляют о своей заинтересованности в его использовании.
  • Помогает вам создать API, который должен сделать обе стороны (сервер и клиент) одинаково счастливыми (или несчастными, но все же они оба равны в своих эмоциях;)).
  • Независимо от языка / технологии — вы можете запустить его как полноценный JAR, использовать его с Spring, Guice или с чем угодно.
  • Помогает ускорить цикл обратной связи как с точки зрения дизайна API, так и с точки зрения совместимости.

связи

Ссылка: AccuREST Stub Runner Выпущен от нашего партнера по JCG Марцина Грэйсчака в блоге для кодирования блогов наркоманов .