---
url: 'https://metadrop.net/es/articulos/mockeando-una-api-de-terceros-en-entornos-de-desarrollo-y-test'
title: 'Mockeando una API de terceros en entornos de desarrollo y test'
author: 'Luis Ruiz'
date: '2022-08-16T08:16:27+00:00'
updated: '2026-06-10T08:27:48+00:00'
type: article
summary: 'Mockeando una API para no depender de la conexión con servicios de terceros en entornos de desarrollo y tests.'
published: true
og:
  determiner: Automatic
  site_name: Metadrop
  'image:alt': 'Mockeando una API de terceros en entornos de desarrollo y test'
  street_address: 'Calle Manuel Luna, 12, 3 Dcha'
  locality: Madrid
  region: Madrid
  postal_code: '28020'
  country_name: España
  email: hola@metadrop.net
  phone_number: '910053180'
schema:
  '@context': 'https://schema.org'
  '@graph':
    -
      '@type': Article
      '@id': 'https://metadrop.net/es/articulos/mockeando-una-api-de-terceros-en-entornos-de-desarrollo-y-test#article'
      name: 'Mockeando una API de terceros en entornos de desarrollo y test'
      headline: 'Mockeando una API de terceros en entornos de desarrollo y test'
      description: 'Mockeando una API para no depender de la conexión con servicios de terceros en entornos de desarrollo y tests.'
      datePublished: '2022-08-16T10:16:27+0200'
      dateModified: '2026-06-10T10:27:48+0200'
      author:
        '@type': Person
        name: 'Luis Ruiz'
      publisher:
        '@type': Organization
        '@id': 'https://metadrop.net/#organization'
      mainEntityOfPage: 'https://metadrop.net/es/articulos/mockeando-una-api-de-terceros-en-entornos-de-desarrollo-y-test'
    -
      '@type': Organization
      '@id': 'https://metadrop.net/#organization'
      url: 'https://metadrop.net/'
      name: Metadrop
      sameAs:
        - 'https://www.drupal.org/metadrop'
        - 'https://twitter.com/metadrop'
        - 'https://asociaciondrupal.es/partner/metadrop'
        - 'https://www.linkedin.com/company/metadrop'
      logo:
        '@type': ImageObject
        url: 'https://metadrop.net/themes/custom/mdrop_radix/logo-metadrop-500-500.jpg'
        width: '500'
        height: '500'
    -
      '@type': ItemPage
      '@id': 'https://metadrop.net/es/articulos/mockeando-una-api-de-terceros-en-entornos-de-desarrollo-y-test'
      breadcrumb:
        '@type': BreadcrumbList
        itemListElement:
          -
            '@type': ListItem
            position: 1
            name: Inicio
            item: 'https://metadrop.net/es'
          -
            '@type': ListItem
            position: 2
            name: 'Artículos expertos sobre Drupal y tecnología'
            item: 'https://metadrop.net/es/articulos'
      publisher:
        '@type': Organization
        '@id': 'https://metadrop.net/#organization'
---
 1. [Artículos](https://metadrop.net/es/articulos)
 
  

# Mockeando una API de terceros en entornos de desarrollo y test

Martes 16 de Agosto de 2022

 

 



Mockeando una API para no depender de la conexión con servicios de terceros en entornos de desarrollo y tests.



   



Buena parte de nuestro trabajo consiste en integrar las herramientas que construimos con servicios de terceros de la forma más eficiente y confiable posible, lo cual implica mantener un código robusto y cubierto por tests. En uno de nuestros proyectos, desarrollamos una funcionalidad que se encargaba de **añadir o eliminar usuarios** a listas de correos gestionadas por **un servicio externo**, con el cual nos comunicamos mediante una API.

En esta ocasión integramos la API utilizando la librería proporcionada por el mismo proveedor, desarrollando además un servicio custom a modo de interface para interactuar con la librería.

La lógica que teníamos que aplicar para decidir cuándo añadir o eliminar usuarios de las múltiples listas era algo compleja, ya que dependía de los diferentes estatus de un usuario, su configuración de cuenta y los roles.

Para el desarrollo y la cobertura de tests automatizados decidimos **duplicar las listas en el servicio externo** para tener versiones distintas de las de producción. El problema surgió cuando, en un determinado momento, los tests de la gestión de las listas empezaron a fallar aleatoriamente. Entonces nos percatamos de que la inconsistencia la generaba el **lanzamiento de tests en paralelo** desde diferentes Merge Requests, ya que estaban actuando sobre las mismas listas.

La solución consistió en mockear la API. En nuestro caso, lo que debíamos mockear no era la API como tal, sino el **servicio custom**. Con esta aproximación **desacoplamos el desarrollo de la integración de la API** propiamente dicha del desarrollo de funcionalidades específicas que dependen del consumo de dicha API.

## Beneficios

- En caso de bugs y con una cobertura de tests adecuada, nos permite **identificar rápidamente** si el problema proviene de la integración de la API o de otra parte del código.
- Poder **desarrollar en paralelo** la integración y otras funcionalidades dependientes de esta.
- **Evitar problemas de inconsistencia** en el lanzamiento de tests automatizados.

## Cómo 

Necesitábamos sobreescribir los métodos de nuestro servicio para que realizara las acciones que precisamos en los entornos de test, así que lo que hicimos fue **crear un módulo custom y “decorar” el servicio original**. Este patrón consiste en añadir o sobrescribir lógica de una clase previamente existente, y que esto sea completamente transparente para el resto del sistema:

 **1.** Configuramos el nuevo servicio en el archivo **module.services.yml** de nuestro módulo:

```json
services: 
  acumbamail_tests.acumbamamil_decorator: 
     class: Drupal\acumbamail_tests\AcumbamailDecorator 
     public: false 
     decorates: acumbamail.client 
     arguments: ["@config.factory", "@logger.factory", "@tempstore.private"]
```

Los parámetros, explicados brevemente, son los siguientes:

- *class*: especificamos la clase.
- *public*: lo seteamos a “false” para que solo se pueda llamar al servicio extendido mediante el servicio decorado.
- *decorates*: el servicio que queremos decorar.
- *arguments*: los argumentos que necesita el servicio decorado, y, si fuera necesario, dependencias que necesitemos en nuestro servicio decorador.

Con esta configuración, cuando se llama al servicio original, se carga el servicio decorador, sin que las clases que lo invoquen tengan que ser modificadas.

 **2.** A continuación, generamos la clase decoradora que extiende la clase decorada, es decir, el servicio original:

```php
<?php

namespace Drupal\acumbamail_tests;

use Drupal\acumbamail\Client\AcumbamailService;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Logger\LoggerChannelFactory;
use Drupal\Core\TempStore\PrivateTempStore;

/**
 * Decorator for the Acumbamail API.
 */

class AcumbamailDecorator extends AcumbamailService {

  /**
   * Cache id.
   *
   * @var string
   */

  protected $storeId = 'acumbamail_tests';


  /**
   * Temp Store.
   *
   * @var \Drupal\Core\TempStore\PrivateTempStore
   */
  protected $tempStorePrivate;

  /**
   * AcumbamailService constructor.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   Config factory.
   * @param \Drupal\Core\Logger\LoggerChannelFactory $logger
   *   Logger.
   * @param \Drupal\Core\TempStore\PrivateTempStore $temp_store_private
   *   Store for subscription data.
   */
  public function __construct(ConfigFactoryInterface $config_factory, LoggerChannelFactory $logger, PrivateTempStore $temp_store_private) {
    parent::__construct($config_factory, $logger);
    $this->tempStorePrivate = $temp_store_private;
  }

  /**
   * Initialize Acumbamail Client.
   */
  protected function initializeClient() {
    if (empty($this->getAuthtoken())) {
      throw new \Exception('Authtoken is not set, please review Acumbamail settings form.');
    }
  }

  /**
   * {@inheritdoc}
   */
  public function subscribeUser(string $list_id, string $user_name, string $user_mail, string $user_verified) {
    $this->initializeClient();
    $data = $this->getData();
    if (!isset($data[$user_mail])) {
      $data[$user_mail] = [];
    }
    $data[$user_mail][$list_id] = TRUE;
    $this->saveData($data);
  }

  /**
   * {@inheritdoc}
   */
  public function unsubscribeUser(string $list_id, string $user_mail) {
    $this->initializeClient();
    $data = $this->getData();
    unset($data[$user_mail][$list_id]);
    $this->saveData($data);
  }

  /**
   * {@inheritdoc}
   */
  public function userIsSubscribed(string $list_id, string $user_mail) {
    $this->initializeClient();
    $data = $this->getData();
    return (isset($data[$user_mail][$list_id]));
  }

  /**
   * Save the data.
   *
   * @param array $data
   *   Data.
   */
  protected function saveData(array $data) {
    $temp_store = $this->tempStorePrivate->get($this->storeId);
    $temp_store->set($this->storeId, $data);
  }

  /**
   * Return data.
   *
   * @return array
   *   Data.
   */
  protected function getData() {
    $temp_store = $this->tempStorePrivate->get($this->storeId);
    $data = $temp_store->get($this->storeId);
    if (empty($data)) {
      $data = [];
    }
    return $data;
  }

}




```

Cabe destacar que en nuestro caso debíamos persistir la asociación de usuarios y listas a través de diferentes peticiones, para ello **utilizamos el servicio “tempstore.private”**.

Con esto, tendríamos terminado el mock y podríamos generar nuestros test apoyándonos en él.

**Tip 1:** Si la integración con la API se realiza directamente, sin utilizar una librería, y se utiliza el servicio http\_client para la gestión de peticiones, puedes aplicar la estrategia explicada por [Daniel Sipos](https://www.webomelette.com/simple-guzzle-api-mocking-functional-testing-drupal-8 "Daniel Sipos").

**Tip 2:** Si quieres que este módulo sea visible solo en ciertos entornos, puedes ubicarlo bajo la carpeta “tests” del módulo principal. Así, solo será visible para Drupal cuando el parámetro ‘extension\_discovery\_scan\_tests’ del settings esté a “true”.

```php
$settings['extension_discovery_scan_tests'] = TRUE;
```





- Luis Ruiz
    
    Senior Drupal Developer
 
[Control de Calidad](https://metadrop.net/es/quienes-somos/metodologia/control-de-calidad " See Control de Calidad")

Metadrop garantiza la calidad mediante pipelines CI/CD, testing automatizado (Behat, PHPUnit), análisis estático de código y revisión por pares en cada proyecto.

 

 Ver más