Puncte:1

Cum îmi bat joc de \Drupal::httpClient()?

drapel jp

Testez o bibliotecă de utilitate (creată de noi) care face apeluri către un API REST extern cu \Drupal::httpClient()

Deci, am o clasă de bibliotecă cu funcții statice:

clasa myUtils {
  funcție publică statică getFromApi($cale)
  {
    ...
    $răspuns = \Drupal::httpClient()->request( ... );
    ...
  }

...

}

și vreau să numesc asta dintr-o clasă de testare:

clasa myUtilsTest extinde \Codeception\Test\Unit
{
  // Multe alte lucruri...
  test de funcție publicăGetFromApi()
  {
     // Fă niște magie batjocoritoare
     ...
     myUtils::getFromApi('/some/test/path');
     ...
  }
}

Îmi dau seama că pot face o \GuzzleHttp\Handler\MockHandler și îl setez să returneze orice vreau, dar cum îl setez să „suprascrie” apelul către \Drupal->httpClient()?

Am văzut câteva exemple care par să presupună că aveți o instanță a unei clase care are propria sa httpClient membru, iar acest lucru este ușor de batjocorit - dar în cazul meu de utilizare, nu există niciun motiv pentru a proiecta utilitățile așa. Deci cum imi bat joc de global \Drupal::httpClient() în acest caz?

Multumesc anticipat pentru orice raspuns.

Kevin avatar
drapel in
Este mai ușor să includeți doar un modul de testare care are un serviciu middleware pentru a oferi răspunsuri pentru orice API intern sau extern. În caz contrar, trebuie să ridicați joc de clasa care este injectată în serviciul pe care îl testați și să bateți joc de fiecare metodă care este utilizată în implementarea dvs.
drapel in
Aceasta este exact situația pentru care aveți nevoie de injecția de dependență, astfel încât API-urile de care depindeți să fie ușor cuplate la codul dvs. și să poată fi batjocorite și schimbate în timpul testării. Odată ce începeți să depindeți de lucruri precum HTTP API, API-ul bazei de date, API-ul entității și prietenii, poate doriți să vă gândiți să puneți instrumentele dvs. într-o clasă de servicii. Aș rezerva funcțiile statice logicii de sine stătătoare (de exemplu, Html.php, Xss.php, UrlHelper.php etc. sunt bune exemple).
drapel jp
OK, mulțumesc, voi lua în considerare! Cu toate acestea, nevoia de a schimba o arhitectură și o implementare perfect validă numai în scopuri de testare mă freacă puțin în sensul greșit. Dar da, ar putea fi o modalitate.
Kevin avatar
drapel in
Utilizarea containerului static în cursuri este descurajată din mai multe motive, acesta este unul dintre ele. Din fericire, nu este prea greu să faci DI.
jbarrio avatar
drapel cn
Sunt de acord cu Patrick și încercând să contribui la asta într-un mod pozitiv, aș spune că tocmai ați găsit ceva de îmbunătățit în implementarea dvs. actuală. Și probabil motivul pentru care vă confruntați cu această problemă se datorează faptului că nu ați implementat soluția dvs. având în vedere o abordare T(B)DD încă de la început. Data viitoare nu ti se va mai intampla asta :_)
drapel jp
Presupun că ești bine! Propria mea experiență de testare este în principal din Python, unde este posibil să batjocoresc ceva mai dinamic, astfel încât designul propriu-zis al codului nu trebuie să ia în considerare testarea (din moment ce puteți testa întotdeauna). Desigur, acesta este Drupal și PHP și nu Python și Django, unde se află experiența mea principală. :-)
Puncte:3
drapel ph

Convertirea clasei dvs. pentru a utiliza injecția de dependență ar arăta cam așa:

utilizați Drupal\Core\Plugin\ContainerFactoryPluginInterface;
utilizați Symfony\Component\DependencyInjection\ContainerInterface;
utilizați GuzzleHttp\Client

clasa myUtils implementează ContainerFactoryPluginInterface {

  /**
   * Serviciul http.
   *
   * @var \GuzzleHttp\Client
   */
  protejat $httpClient;

  funcția publică finală __construct(matrice $configurație, $id_plugin, $definiție_plugin, Client $httpClient) {
    $this->httpClient = $httpClient;
    parent::__construct($configuration, $plugin_id, $plugin_definition);
  }

  funcția publică statică create(ContainerInterface $container, matrice $configurație, $plugin_id, $plugin_definition) {
    returnează static nou (
      $configurare,
      $plugin_id,
      $plugin_definition,
      $container->get('http_client')
    );
  }

  funcția publică getFromApi($cale)
  {
    ...
    $răspuns = $this->httpClient->request( ... );
    ...
  }

...

}

Postează un răspuns

Majoritatea oamenilor nu înțeleg că a pune multe întrebări deblochează învățarea și îmbunătățește legătura interpersonală. În studiile lui Alison, de exemplu, deși oamenii își puteau aminti cu exactitate câte întrebări au fost puse în conversațiile lor, ei nu au intuit legătura dintre întrebări și apreciere. În patru studii, în care participanții au fost implicați în conversații ei înșiși sau au citit transcrieri ale conversațiilor altora, oamenii au avut tendința să nu realizeze că întrebarea ar influența – sau ar fi influențat – nivelul de prietenie dintre conversatori.