Решения для макета интерфейса Dubbo

Java

задний план

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

Чтобы лучше понять нашу потребность в моках, давайте сначала посмотрим на объяснение автоматического тестирования в вики.

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

Наши автоматические тесты выполняются в соответствии с нашим предустановленным процессом, и мы не хотим, чтобы на нас влияли сторонние сервисы (вверх-вниз, интерфейс возвращает неверные данные), поэтому при вызове стороннего интерфейса мы будем использовать mock и вернуть то, что мы ожидаем данные.

В автоматизированном тесте мы издевались над тремя интерфейсами http, dubbo и mq message, В этой статье объясняется наше решение для имитации интерфейса dubbo.

В настоящее время Dubbo предлагает решения

Во-первых, давайте взглянем на фиктивные функции, предоставляемые самим фреймворком dubbo.

Основной код функции dubbo mock выглядит следующим образом.

//from MockClusterInvoker
public Result invoke(Invocation invocation) throws RpcException {
        Result result = null;

        //获取方法级别mock配置
        String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), Constants.MOCK_KEY, Boolean.FALSE.toString()).trim();
        //没有配置 或者 =false
        if (value.length() == 0 || value.equalsIgnoreCase("false")) {
            //no mock
            result = this.invoker.invoke(invocation);
        } else if (value.startsWith("force")) {
            // force 开头 强制进行mock
            if (logger.isWarnEnabled()) {
                logger.warn("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl());
            }
            //force:direct mock
            result = doMockInvoke(invocation, null);
        } else {
            //不是force的话 是失败了再进行mock
            //fail-mock
            try {
                result = this.invoker.invoke(invocation);
            } catch (RpcException e) {
                //如果是业务异常不进行mock
                if (e.isBiz()) {
                    throw e;
                }
                
                if (logger.isWarnEnabled()) {
                    logger.warn("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + directory.getUrl(), e);
                }
                result = doMockInvoke(invocation, e);
            }
        }
        return result;
    }

В соответствии с разницей соответствующего значения key=mock в URL-адресе существует три вида логики соответственно.

  1. value = null не издевайтесь
  2. value = force xxx принудительно использовать фиктивную логику
  3. value = xxx пройти фиктивную логику после того, как служба не будет вызвана

Глядя на третью логику, чувствуете ли вы, что это на самом деле даунгрейд, отказ от даунгрейда, а вторая логика называется принудительным даунгрейдом.

Официальная документация, предоставленная dubbo, также определяет этот макет как даунгрейд.

image.png

Если вы хотите узнать, как настроить выражения Dubbo Mock, вы можете увидетьАнализ исходного кода Dubbo с пониженной версией Mock

Соответствует ли это нашим потребностям

Наши потребности

  1. Независимо от того, находится ли третья сторона в сети или нет, это не влияет на наши макеты.
  2. Гибкая и простая конфигурация

После тестирования, после установки check=false и настройки mock=force:return null для интерфейса, если провайдер не в сети, будет выброшено исключение no provider, что не соответствует требованию 1.

Метод тестирования: добавьте следующую конфигурацию в официальную демонстрацию dubbo.

//from DemoServiceComponent
@Reference(mock = "force:return null",check = false)
private DemoService demoService;

Для требования 2 также существуют следующие проблемы

  1. Мы не можем переместить конфигурацию dubbo в исходный проект, поэтому мы можем вызвать принудительный макет, только добавив конфигурацию переопределения в реестр dubbo, что неудобно для использования.
  2. Из пункта 1 также видно, что фиктивная функция зависит от реестра.Наша фиктивная среда и тестовая среда используют один и тот же реестр, что невозможно.
  3. Документ фиктивного значения недостаточно детализирован, а построение трудоемко для возврата сложных типов.

Таким образом, вывод состоит в том, что ни реализация, ни использование не могут удовлетворить наши потребности.Функция mock Dubbo по-прежнему ориентирована на требования понижения уровня производства.Нам необходимо разработать mock-решение, которое нам будет удобно использовать.

Решения по расширению, разработанные нами

Конструктивные точки макетной схемы, которую мы разработали для фреймворка dubbo, следующие:

  1. То же использование класса-оболочки точки расширения Cluster для имплантации фиктивной логики, чтобы гарантировать, что автономный сервис не повлияет на наш автоматический запуск теста.
  2. Используйте файл конфигурации свойств для управления фиктивным переключателем интерфейса, конфигурация может быть размещена в apollo, без вторжения кода.
  3. Перенаправьте запрос на наш сервер EsayMock и настройте данные Json типа возврата интерфейса.

image.png
image.png

Могу ли я использовать фильтр для этого?

Я видел подобное решение в Интернете до того, как реализовал его с помощью Filter.На самом деле, наша первая версия также использует для этого Filter, но есть проблема.Провайдер нашего mock-интерфейса должен быть в сети.

Ниже объясняется, почему эта проблема возникает с точки зрения исходного кода.

При условии использования zookeeper в качестве центра регистрации и check=false

Логика фильтра внедряется через класс-оболочку протокола, ProtocolFilterWrapper.ProtocolFilterWrapper внедряет логику цепочки вызовов фильтра для других протоколов, кроме RegistryProtocol.

//from ProtocolFilterWrapper
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
    if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
        return protocol.refer(type, url);
    }
    return buildInvokerChain(protocol.refer(type, url), Constants.REFERENCE_FILTER_KEY, Constants.CONSUMER);
}

Проблема кроется в RegistryProtocol.RegistryProtocol косвенно зависит от DubboProtocl через модули Cluster и Directory.В модуле Directory, то есть RegistryDirectory, будет проверяться количество провайдеров.Если будет 0, то будет брошено исключение . Все это происходит до вызова вызывающей программы, сгенерированной DubboProtocl.

Инициатор, сгенерированный DubboProtocol, инкапсулирует логику фильтрации и вызывает логику к удаленным службам.

Invoekr, созданный RegistryProtcol, инкапсулирует функции управления услугами, такие как вызов кластера и балансировка нагрузки на основе DubboProtocol.

//from RegistryDirectory

private void refreshInvoker(List<URL> invokerUrls) {
        Assert.notNull(invokerUrls, "invokerUrls should not be null");
		//这边为什么是一个,针对没有提供者目录,dubbo框架会自动返回一个empty的url
        if (invokerUrls.size() == 1
                && invokerUrls.get(0) != null
                && Constants.EMPTY_PROTOCOL.equals(invokerUrls.get(0).getProtocol())) {
            this.forbidden = true; // Forbid to access
            this.invokers = Collections.emptyList();
            routerChain.setInvokers(this.invokers);
            destroyAllInvokers(); // Close all invokers
        }
    	//...
}

public List<Invoker<T>> doList(Invocation invocation) {
        if (forbidden) {
            // 1. No service provider 2. Service providers are disabled
            throw new RpcException(RpcException.FORBIDDEN_EXCEPTION, "No provider available from registry " +
                    getUrl().getAddress() + " for service " + getConsumerUrl().getServiceKey() + " on consumer " +
                    NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() +
                    ", please check status of providers(disabled, not registered or in blacklist).");
        }
    	//...
}

Друзья, которые не читали исходный код dubbo, могут его не понять, вы можете попробовать его после прочтения принципа dubbo refer

недостаточный

Интерфейсы json и dubbo на мок-сервере не сильно связаны, но это не большая проблема, мы все запускаем предустановленный процесс.

проект с открытым исходным кодом

Так много было сказано, все это принципиальное содержание, и ссылка прикреплена ниже, и каждый может использовать ее и вносить предложения.

адрес проекта dubbo-easy-mock

Ссылаться на

Документация Dubbo - понижение обслуживания