{"id":230488,"date":"2022-11-27T14:50:00","date_gmt":"2022-11-27T11:50:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=230488"},"modified":"2022-11-27T14:50:49","modified_gmt":"2022-11-27T11:50:49","slug":"escrevendo-testes-unitarios-com-phpunit-parte-2-the-tear-down","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/pt-pt\/escrevendo-testes-unitarios-com-phpunit-parte-2-the-tear-down\/","title":{"rendered":"Escrevendo Testes Unit\u00e1rios com PHPUnit, Parte 2: The Tear Down"},"content":{"rendered":"\n<p><strong><a href=\"https:\/\/wordpress.mediadoma.com\/pt-pt\/escrevendo-testes-de-unidade-com-phpunit-parte-1-a-configuracao\/\" title=\"No final do m\u00eas passado\">No final do m\u00eas passado<\/a><\/strong>, comecei a falar sobre escrever testes de unidade em PHPUnit para c\u00f3digo baseado em WordPress. Isso incluiu principalmente a ideia de configurar o <strong><a href=\"https:\/\/phpunit.de\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">PHPUnit<\/a><\/strong>, a <strong>fun\u00e7\u00e3o setUp<\/strong> e escrever testes b\u00e1sicos.<\/p>\n<p>Isso, no entanto, n\u00e3o discutiu o que eu sei sobre a fun\u00e7\u00e3o <strong>tearDown<\/strong>, que ainda \u00e9 um recurso importante de escrever usando testes. Al\u00e9m disso, tamb\u00e9m h\u00e1 duas maneiras de considerar escrever testes para projetos do WordPress.<\/p>\n<p>Nomeadamente:<\/p>\n<ol>\n<li>escrever testes especificamente para plugins e funcionalidade da camada de aplica\u00e7\u00e3o,<\/li>\n<li>executando testes de unidade no aplicativo WordPress.<\/li>\n<\/ol>\n<p>Antes de avan\u00e7ar com este post em particular, por\u00e9m, recomendo atualizar o que abordei at\u00e9 agora. Isso inclui as seguintes postagens:<\/p>\n<ol>\n<li><strong><a href=\"https:\/\/wordpress.mediadoma.com\/pt-pt\/um-ambiente-de-desenvolvimento-wordpress-usando-um-gerenciador-de-pacotes\/\" title=\"Um ambiente de desenvolvimento WordPress (usando um gerenciador de pacotes)\">Um ambiente de desenvolvimento WordPress (usando um gerenciador de pacotes)<\/a><\/strong><\/li>\n<li><a href=\"https:\/\/wordpress.mediadoma.com\/pt-pt\/um-ide-para-desenvolvimento-wordpress-independentemente-da-experiencia\/\" title=\"Um IDE para desenvolvimento WordPress\">Um IDE para desenvolvimento WordPress<\/a><\/li>\n<li><strong><a href=\"https:\/\/wordpress.mediadoma.com\/pt-pt\/trabalhando-com-configuracoes-de-usuario-no-visual-studio-code\/\" title=\"Trabalhando com configura\u00e7\u00f5es de usu\u00e1rio no Visual Studio Code\">Trabalhando com configura\u00e7\u00f5es de usu\u00e1rio no Visual Studio Code<\/a><\/strong><\/li>\n<li><a href=\"https:\/\/wordpress.mediadoma.com\/pt-pt\/escrevendo-testes-de-unidade-com-phpunit-parte-1-a-configuracao\/\" title=\"Escrevendo testes de unidade com PHPUnit, parte 1: a configura\u00e7\u00e3o\">Escrevendo testes de unidade com PHPUnit, parte 1: a configura\u00e7\u00e3o<\/a><\/li>\n<\/ol>\n<p>Depois de fazer isso, volte a este post e vamos continuar discutindo a fun\u00e7\u00e3o tearDown e como s\u00e3o os testes de unidade no contexto do WordPress.<\/p>\n<h2>Testes Unit\u00e1rios com PHPUnit, Parte 2: A Destrui\u00e7\u00e3o<\/h2>\n<p>Antes de prosseguir, lembre-se de que os desenvolvedores geralmente tratam a fun\u00e7\u00e3o <strong>setUp<\/strong> como o construtor e a fun\u00e7\u00e3o <strong>tearDown<\/strong> como um destruidor; no entanto, lembre-se de que o \u00faltimo nem sempre \u00e9 necess\u00e1rio.<\/p>\n<p>Aqui est\u00e1 uma boa regra para lembrar:<\/p>\n<ul>\n<li>Qualquer coisa que uma fun\u00e7\u00e3o de teste precise chamar\u00e1 a fun\u00e7\u00e3o <strong>setUp<\/strong> para que as classes necess\u00e1rias sejam necess\u00e1rias.<\/li>\n<li>A fun\u00e7\u00e3o <strong>tearDown<\/strong> nem sempre \u00e9 necess\u00e1ria, pois a fun\u00e7\u00e3o <strong>setUp<\/strong> pode reinicializar uma classe.<\/li>\n<\/ul>\n<p>Ent\u00e3o, o que isso significa para a fun\u00e7\u00e3o <strong>tearDown<\/strong> se ela n\u00e3o estiver redefinindo os dados criados durante a fun\u00e7\u00e3o <strong>setUp<\/strong>? <\/p>\n<h3>1 A fun\u00e7\u00e3o de desmontagem<\/h3>\n<p>O melhor conselho que posso dar sobre a fun\u00e7\u00e3o <strong>tearDown<\/strong> \u00e9 que ela deve ser usada se algo for configurado durante um dos testes que for deixado para tr\u00e1s.<\/p>\n<p>Isso pode ser algo gravado em um banco de dados, algo gravado em um log ou, mais geralmente, algo gravado no disco r\u00edgido.<\/p>\n<p>Assim, se um teste gravar um registro ou arquivo, o m\u00e9todo <strong>tearDown<\/strong> ser\u00e1 executado ap\u00f3s um teste e dever\u00e1 remover qualquer teste gravado na unidade que n\u00e3o fa\u00e7a parte do teste, mas n\u00e3o seja permanentemente necess\u00e1rio para o pr\u00f3ximo teste ou que deve ser limpo depois de si mesmo.<\/p>\n<p>Ent\u00e3o, de certa forma, \u00e9 como um <strong><a href=\"http:\/\/en.cppreference.com\/w\/cpp\/language\/destructor\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">destruidor<\/a><\/strong>, mas se voc\u00ea nunca usou uma linguagem que tenha um destruidor, essa nomenclatura parece irrelevante ou n\u00e3o faz sentido.<\/p>\n<blockquote>\n<p>Um <strong>destruidor<\/strong> \u00e9 uma fun\u00e7\u00e3o de membro especial que \u00e9 chamada quando o tempo de vida de um objeto termina. O objetivo do <strong>destruidor<\/strong> \u00e9 liberar os recursos que o objeto pode ter adquirido durante sua vida \u00fatil.<\/p>\n<\/blockquote>\n<p>Assim, talvez seja melhor simplesmente pensar na fun\u00e7\u00e3o como uma forma de limpeza ap\u00f3s um teste (e n\u00e3o no sentido de definir uma vari\u00e1vel igual a nula, pois a fun\u00e7\u00e3o <strong>setUp<\/strong> pode fazer isso).<\/p>\n<h3>2 testes de unidade para projetos WordPress<\/h3>\n<p>Ao escrever testes de unidade para projetos do WordPress, temos que ter certeza de que estamos sendo claros sobre o tipo de teste de unidade sobre o qual estamos falando.<\/p>\n<p>Por exemplo, o que chamarei de testes unit\u00e1rios cl\u00e1ssicos ou padr\u00e3o seguem a metodologia de &#8220;desenvolvimento orientado a testes&quot; sobre a qual falarei em breve. Por outro lado, o WordPress tem seu pr\u00f3prio conjunto de testes de unidade para temas e afins, sobre os quais tamb\u00e9m falarei um pouco mais adiante neste post.<\/p>\n<p>Mas para esta se\u00e7\u00e3o, achei que poderia ser \u00fatil falar um pouco sobre o primeiro em vez do segundo, para que voc\u00ea possa ver como isso pode funcionar.<\/p>\n<p>No exemplo abaixo, estou escrevendo testes em um plugin que \u00e9 respons\u00e1vel por se comunicar com uma API de terceiros. Este plugin em particular requer um nome de usu\u00e1rio e senha ou uma API <strong>e<\/strong> queremos ter certeza de que, para os prop\u00f3sitos deste post, ele est\u00e1 recuperando corretamente um erro sempre que o teste for executado.<\/p>\n<p>Observe que ao ler este c\u00f3digo, voc\u00ea me ver\u00e1 falar um pouco sobre reflex\u00e3o. Eu vou fazer um post inteiro sobre PHP Reflection em breve, ent\u00e3o ele vai esclarecer um pouco sobre isso.<\/p>\n<p>No entanto, para o c\u00f3digo abaixo, suponha que seja uma maneira de obter acesso a propriedades marcadas como privadas.<\/p>\n<p>Lembre-se do \u00faltimo post desta s\u00e9rie, tivemos um teste inicial que se parecia <strong><a href=\"https:\/\/gist.github.com\/tommcfarlin\/248c7741273e6be414c1f98c11085fe7#file-01-acme-cache-test-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">com isso:<\/a><\/strong><\/p>\n<pre><code>&lt;?php\n\nuse PHPUnitFrameworkTestCase;\n\nclass AcmeCacheTest extends TestCase\n{\n  protected $cache;\n\n  protected function setUp()\n  {\n    $this-&gt;cache = new AcmeCache();\n  }\n\n  public function testDefaultDuration()\n  {\n    $this-&gt;assertTrue($this-&gt;cache-&gt;getDuration() === 43200);\n  }\n\n  public function testNewDuration()\n  {\n    $this-&gt;cache-&gt;setDuration(1000);\n\n    $this-&gt;assertFalse($this-&gt;cache-&gt;getDuration() === 43200);\n    $this-&gt;assertTrue($this-&gt;cache-&gt;getDuration() === 1000);\n  }\n\n  \/\/ More to come...\n}<\/code><\/pre>\n<p>Observe, no entanto, que neste teste n\u00e3o h\u00e1 fun\u00e7\u00e3o <strong>tearDown<\/strong> que fa\u00e7a sentido, certo? Afinal, nada est\u00e1 sendo gravado em um banco de dados ou em um arquivo.<\/p>\n<p>Mas digamos que queremos apresentar um caso de teste que ter\u00e1 um nome de arquivo, conte\u00fado e gravar\u00e1 o conte\u00fado no arquivo. Nesse caso, ser\u00e3o dados est\u00e1ticos, mas tecnicamente podem ser qualquer coisa gravada em disco.<\/p>\n<h4>1 Configurando o Teste<\/h4>\n<p><strong><a href=\"https:\/\/gist.github.com\/tommcfarlin\/ca4f83191255e661a84e3563b27263de#file-00-initial-set-up-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Primeiro<\/a><\/strong>, queremos configurar o teste definindo o nome do arquivo, o conte\u00fado do arquivo e preparando as propriedades.<\/p>\n<pre><code>&lt;?php\n\nnamespace PresswareAcmeTestsAPI;\n\nuse PHPUnitFrameworkTestCase;\n\nclass AcmeFileTest extends TestCase\n{\n\n  private $filename;\n\n  private $content;\n\n  public function setUp()\n  {\n    $this-&gt;filename = 'testFile.txt';\n    $this-&gt;content = 'This is a string of data that is meant to be written to the file.';\n  }\n\n  \/\/ More to come...\n}\n<\/code><\/pre>\n<p>F\u00e1cil o suficiente, certo?<\/p>\n<h4>2 Gravar e Ler Dados<\/h4>\n<p>Em seguida, queremos escrever os dados, ler os dados e afirmar que o conte\u00fado <strong><a href=\"https:\/\/gist.github.com\/tommcfarlin\/ca4f83191255e661a84e3563b27263de#file-01-testing-contents-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">\u00e9 o mesmo.<\/a><\/strong><\/p>\n<pre><code>&lt;?php\n\nnamespace PresswareAcmeTestsAPI;\n\nuse PHPUnitFrameworkTestCase;\n\nclass AcmeFileTest extends TestCase\n{\n\n  private $filename;\n\n  private $content;\n\n  public function setUp()\n  {\n    $this-&gt;filename = 'testFile.txt';\n    $this-&gt;content = 'This is a string of data that is meant to be written to the file.';\n  }\n\n  public function testWriteReadData()\n  {    \n    \/\/ Writes the content to the file with the given filename.\n    $fileHandle = fopen($this-&gt;filename, 'w');\n    fwrite($fileHandle, $this-&gt;content);\n    fclose($fileHandle);\n\n    \/\/ Reads the contents of the file that was just written\n    $fileHandle = fopen($this-&gt;filename, 'r');\n    $contents = fread($fileHandle, filesize($this-&gt;filename));\n    fclose($fileHandle);\n\n    $this-&gt;assertSame($this-&gt;content, $contents);\n  }\n\n  \/\/ More to come..\n}\n<\/code><\/pre>\n<p>Neste ponto, se voc\u00ea executar o teste (que ainda n\u00e3o abordei tecnicamente sobre como fazer), voc\u00ea notar\u00e1 que <strong>testFile.txt<\/strong> ainda reside em seu sistema.<\/p>\n<h4>3 Usando desmontagem<\/h4>\n<p>Por fim, precisamos trabalhar com o m\u00e9todo <strong>tearDown<\/strong> para garantir que o arquivo seja exclu\u00eddo ap\u00f3s a conclus\u00e3o do teste de unidade. <strong><a href=\"https:\/\/gist.github.com\/tommcfarlin\/ca4f83191255e661a84e3563b27263de#file-02-full-test-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Veja como pode ficar<\/a><\/strong> se voc\u00ea implementou seu c\u00f3digo como o que voc\u00ea v\u00ea acima.<\/p>\n<pre><code>&lt;?php\n\nnamespace PresswareAcmeTestsAPI;\n\nuse PHPUnitFrameworkTestCase;\n\nclass AcmeFileTest extends TestCase\n{\n\n  private $filename;\n\n  private $content;\n\n  public function setUp()\n  {\n    $this-&gt;filename = 'testFile.txt';\n    $this-&gt;content = 'This is a string of data that is meant to be written to the file.';\n  }\n\n  public function testWriteReadData()\n  {    \n    \/\/ Writes the content to the file with the given filename.\n    $fileHandle = fopen($this-&gt;filename, 'w');\n    fwrite($fileHandle, $this-&gt;content);\n    fclose($fileHandle);\n\n    \/\/ Reads the contents of the file that was just written\n    $fileHandle = fopen($this-&gt;filename, 'r');\n    $contents = fread($fileHandle, filesize($this-&gt;filename));\n    fclose($fileHandle);\n\n    $this-&gt;assertSame($this-&gt;content, $contents);\n  }\n\n  public function tearDown()\n  {\n    if (file_exists($this-&gt;filename)) {\n      unlink($this-&gt;filename);\n    }\n  }\n}\n<\/code><\/pre>\n<p>Observe que no m\u00e9todo <strong>tearDown<\/strong>, primeiro verifico se um <a href=\"https:\/\/php.net\/manual\/en\/function.file-exists.php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">file_exists<\/a>. Isso ocorre porque se voc\u00ea simplesmente tentar <a href=\"https:\/\/php.net\/manual\/en\/function.unlink.php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">desvincular<\/a> um arquivo que n\u00e3o est\u00e1 presente, receber\u00e1 um erro ao executar seus testes porque, se <strong>o tearDown<\/strong> estiver presente, ele tentar\u00e1 excluir algo ap\u00f3s cada fun\u00e7\u00e3o de teste. E se o arquivo n\u00e3o existir, ent\u00e3o n\u00e3o h\u00e1 nada para deletar e, portanto, resultar\u00e1 em um problema.<\/p>\n<p>Portanto, na tentativa de escrever c\u00f3digo defensivamente, acredito que seja respons\u00e1vel por verificar se o arquivo existe antes de tentar exclu\u00ed-lo.<\/p>\n<h3>3 Ordem de Opera\u00e7\u00f5es<\/h3>\n<p>Quando se trata de testes unit\u00e1rios puros, voc\u00ea normalmente ler\u00e1 isso em termos de <strong><a href=\"https:\/\/en.wikipedia.org\/wiki\/Test-driven_development\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">desenvolvimento orientado a testes<\/a><\/strong>. Este \u00e9 um grande t\u00f3pico em si; no entanto, vale a pena mencionar aqui se voc\u00ea optar por pesquis\u00e1-lo mais e at\u00e9 mesmo implement\u00e1-lo em seus esfor\u00e7os de desenvolvimento.<\/p>\n<p>A ideia geral por tr\u00e1s dessa abordagem \u00e9 frequentemente chamada de &#8220;repeti\u00e7\u00e3o vermelha-verde&#8221;. E n\u00e3o estou negando, h\u00e1 algo nessa abordagem. Ou seja, ele permite que voc\u00ea, como desenvolvedor, escreva o c\u00f3digo como voc\u00ea espera que funcione antes de realmente escrever o c\u00f3digo.<\/p>\n<p>A psicologia por tr\u00e1s disso \u00e9 esta: se voc\u00ea sabe como o c\u00f3digo funciona, \u00e9 mais prov\u00e1vel que voc\u00ea escreva testes que passem; ao passo que, se voc\u00ea escrever testes de como o c\u00f3digo deve ser executado, dever\u00e1 escrever um c\u00f3digo melhor.<\/p>\n<p>Infelizmente, nem sempre temos esse luxo. Mas isso n\u00e3o significa que devemos jogar fora o proverbial beb\u00ea junto com a \u00e1gua. Em vez disso, sou da opini\u00e3o de que voc\u00ea deve escrever testes quando puder e escrever o c\u00f3digo depois; caso contr\u00e1rio, escreva seus testes ap\u00f3s seu c\u00f3digo.<\/p>\n<p>Em \u00faltima an\u00e1lise, ter testes em vigor, independentemente, ser\u00e1 melhor do que nenhum teste.<\/p>\n<h3>4 Testando com WordPress<\/h3>\n<p>Quando se trata de teste de unidade no WordPress, h\u00e1 algumas coisas que voc\u00ea provavelmente j\u00e1 encontrou. \u00c0s vezes, o conte\u00fado \u00e9 um nome impr\u00f3prio ou pode at\u00e9 ser enganoso em termos de &#8220;teste de unidade no WordPress&#8221;.<\/p>\n<p><a href=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-164139-61e75e67162bf.png\" data-rel=\"lightbox\"><img decoding=\"async\" class=\"SDStudio-light-box-enable SDStudio-editor-tools-md-imp\" src=\"https:\/\/wordpress.mediadoma.com\/wp-content\/uploads\/2022\/01\/post-164139-61e75e67162bf.png\" alt=\"Escrevendo Testes Unit\u00e1rios com PHPUnit, Parte 2: The Tear Down\"><\/a><\/p>\n<p>Caso em quest\u00e3o, h\u00e1 duas coisas dignas de nota:<\/p>\n<ol>\n<li><strong><a href=\"https:\/\/codex.wordpress.org\/Theme_Unit_Test\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">O Teste de Unidade de Tema<\/a><\/strong>. Esse conjunto espec\u00edfico de conte\u00fado destina-se a ajudar os desenvolvedores de temas a testar todos os casos principais e secund\u00e1rios de seus temas. N\u00e3o h\u00e1 ferramentas automatizadas, por exemplo, que voc\u00ea usaria como no que discutimos acima.<\/li>\n<li><strong><a href=\"https:\/\/make.wordpress.org\/core\/handbook\/testing\/automated-testing\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Testes Automatizados<\/a><\/strong>. O WordPress vem com seu pr\u00f3prio conjunto de testes de unidade para que n\u00e3o tenhamos que escrever testes contra a maioria das funcionalidades do WordPress (como se as fun\u00e7\u00f5es da API funcionam ou n\u00e3o conforme o esperado). Isso nos permite focar em escrever testes de unidade para nossa pr\u00f3pria l\u00f3gica de dom\u00ednio.<\/li>\n<li><strong><a href=\"https:\/\/make.wordpress.org\/cli\/handbook\/plugin-unit-tests\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Testes de unidade de plug-in<\/a><\/strong>. Se voc\u00ea usou o WP-CLI (ou est\u00e1 interessado nele), provavelmente leu esta p\u00e1gina ou at\u00e9 mesmo usou essas ferramentas. \u00c9 \u00fatil, mas tamb\u00e9m visa aspectos espec\u00edficos do teste de plugins do WordPress.<\/li>\n<\/ol>\n<p>Todos os itens acima s\u00e3o informa\u00e7\u00f5es \u00fateis e n\u00e3o estou dizendo que devam ser ignorados. Em vez disso, deve ser combinado com o restante das informa\u00e7\u00f5es usadas ao longo deste post.<\/p>\n<h2>Executando testes de unidade<\/h2>\n<p>No pr\u00f3ximo post, mostrarei tudo o que voc\u00ea precisa saber para configurar um arquivo XML que informar\u00e1 ao PHPUnit onde os testes residem e como execut\u00e1-los.<\/p>\n<p>Por enquanto, por\u00e9m, revise o c\u00f3digo que est\u00e1 neste post e prepare-se para constru\u00ed-lo no pr\u00f3ximo post desta s\u00e9rie.<\/p>\n<p><div id=\"PostUnique_PostSource\" style=\"padding-top: 50px\">Fonte de grava\u00e7\u00e3o:  <a target=\"_blank\" rel=\"noopener nofollow\" href=\"\/\/tommcfarlin.com\" class=\"external external_icon\">tommcfarlin.com<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Um tutorial sobre como escrever testes de unidade que aproveitam adequadamente os m\u00e9todos setUp e tearDown do PHPUnit.<\/p>\n","protected":false},"author":1,"featured_media":164140,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_wp_rev_ctl_limit":""},"categories":[722,806,846],"tags":[1170],"class_list":["post-230488","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-desenvolvedor","category-php-8","category-tutoriais","tag-affiai-pt-pt"],"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/posts\/230488","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/comments?post=230488"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/posts\/230488\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/media\/164140"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/media?parent=230488"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/categories?post=230488"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/tags?post=230488"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}