<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Raphaël Anic-Antic</title>
    <description>The latest articles on DEV Community by Raphaël Anic-Antic (@rafatic).</description>
    <link>https://dev.to/rafatic</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F5261%2Fb38b9837-8ef7-4e79-9759-cf075cb84bea.jpg</url>
      <title>DEV Community: Raphaël Anic-Antic</title>
      <link>https://dev.to/rafatic</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rafatic"/>
    <language>en</language>
    <item>
      <title>Authentification Oauth2 avec OpenFeign</title>
      <dc:creator>Raphaël Anic-Antic</dc:creator>
      <pubDate>Tue, 17 Oct 2023 19:47:10 +0000</pubDate>
      <link>https://dev.to/rafatic/authentification-oauth2-avec-openfeign-492o</link>
      <guid>https://dev.to/rafatic/authentification-oauth2-avec-openfeign-492o</guid>
      <description>&lt;h2&gt;
  
  
  Contexte
&lt;/h2&gt;

&lt;p&gt;OpenFeign est une libraire du projet Spring Cloud permettant de développer des clients HTTP de manière déclarative. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note : &lt;a href="https://spring.io/projects/spring-cloud-openfeign"&gt;Spring Cloud OpenFeign&lt;/a&gt; n'est pas à confondre avec &lt;a href="https://github.com/OpenFeign/feign"&gt;Feign&lt;/a&gt;. En effet, le premier est une surcouche du second offrant une integration au reste de l'écosystème Spring&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Dans cet article, nous allons voir comment configurer OpenFeign pour gérer une authentification Oauth2 de manière transparente en se basant sur l'autoconfiguration de Spring Security&lt;/p&gt;

&lt;h2&gt;
  
  
  Spring Security
&lt;/h2&gt;

&lt;p&gt;Spring Security permet de gérer l'authentification Oauth2 à un service via son autoconfiguration.&lt;br&gt;
Pour se faire, un simple configuration de propriétés dans le fichier &lt;code&gt;application.properties&lt;/code&gt; est nécessaire :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spring.security.oauth2.client.registration.XXX.client-id=${client_id}
spring.security.oauth2.client.registration.XXX.client-secret=${client_secret}
spring.security.oauth2.client.registration.XXX.authorization-grant-type=client_credentials
spring.security.oauth2.client.registration.XXX.scope=${scope_list}
spring.security.oauth2.client.provider.XXX.token-uri=${token_uri}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;XXX&lt;/code&gt; représente le nom du &lt;code&gt;clientRegistrationId&lt;/code&gt; utilisé par Spring Security et OpenFeign.&lt;/p&gt;

&lt;p&gt;Vous pouvez lui donner le nom de votre choix. D'autre part, vous pouvez configurer différentes authentification Oauth2 en utilisant différents &lt;code&gt;clientRegistrationId&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;La configuration ci dessus active l'authentification Oauth2 pour Spring Security et &lt;code&gt;RestTemplate&lt;/code&gt; (client HTTP par défaut de Spring). &lt;/p&gt;

&lt;p&gt;Cependant, nous souhaitons utiliser OpenFeign et pas &lt;code&gt;RestTemplate&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenFeign
&lt;/h2&gt;

&lt;p&gt;OpenFeign étant une librairie du projet Spring Cloud, elle dispose de configuration lui permettant de s'intégrer au reste du framework Spring (donc Spring Security).&lt;/p&gt;

&lt;p&gt;Pour activer cette intégration, les deux lignes suivantes doivent être ajoutées à votre fichier &lt;code&gt;application.properties&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spring.cloud.openfeign.oauth2.enabled=true
spring.cloud.openfeign.oauth2.clientRegistrationId=XXX
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nous retrouvons ici le fameux &lt;code&gt;clientRegistrationId&lt;/code&gt;. Celui ci doit être le même que celui configuré pour Spring Security.&lt;/p&gt;

&lt;p&gt;Grace à cette configuration, OpenFeign peut gérer automatiquement l'authentification Oauth2 ainsi que le rafraichissement de token.&lt;/p&gt;

</description>
      <category>java</category>
      <category>spring</category>
      <category>openfeign</category>
      <category>oauth2</category>
    </item>
    <item>
      <title>GWT : une astuce simple pour des tests simples</title>
      <dc:creator>Raphaël Anic-Antic</dc:creator>
      <pubDate>Tue, 17 Oct 2023 18:46:06 +0000</pubDate>
      <link>https://dev.to/rafatic/gwt-une-astuce-simple-pour-des-tests-simples-215l</link>
      <guid>https://dev.to/rafatic/gwt-une-astuce-simple-pour-des-tests-simples-215l</guid>
      <description>&lt;p&gt;Dans cette série de posts sur l'assurance qualité, je voulais vous partager un format simple à mettre en place pour rendre vos tests plus lisibles et potentiellement détecter des erreurs de conception.&lt;/p&gt;

&lt;h2&gt;
  
  
  Given When Then
&lt;/h2&gt;

&lt;p&gt;Given When Then (ou GWT) est un format simple qui définit les trois étapes obligatoires d'un test. &lt;/p&gt;

&lt;p&gt;En effet, lorsque nous rédigeons un test, nous implémentons toujours les trois mêmes étapes : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mise en place de l'état du système (initialisation)&lt;/li&gt;
&lt;li&gt;Action sur le système (exécution)&lt;/li&gt;
&lt;li&gt;Observation du nouvel état du système (assertion)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Les sources de notre test peuvent représenter ces trois étapes en les divisant par de simples commentaires :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Given
Person p = new Person("john", "Doe", 22);
PersonService service = new PersonService();

// When
boolean isAdult = service.isAdult(p);

// Then
assertThat(isAdult).isTrue();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Given
&lt;/h3&gt;

&lt;p&gt;Cette partie regroupe toutes les étapes nécessaires à l'initialisation du test. Elle décrit l'état du système précédant l'exécution. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Cette partie peut être vide (ex : si notre système n'a pas d'état)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Si cette partie est grande et/ou complexe, alors cela peut :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mettre en évidence un système trop complexe &lt;/li&gt;
&lt;li&gt;indiquer un périmètre de test trop grand.&lt;/li&gt;
&lt;li&gt;se traduire en un test instable (flaky)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When
&lt;/h3&gt;

&lt;p&gt;Il s'agit de l'action sur le système. Généralement peut être résumée en un seul appel de méthode.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Si plusieurs appels de méthodes sont nécessaires pour rendre le test intéressant, alors cela peut signifier que 

&lt;ul&gt;
&lt;li&gt;le code à tester est trop complexe / factorisé &lt;/li&gt;
&lt;li&gt;le périmètre de test peut encore être réduit.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Then
&lt;/h3&gt;

&lt;p&gt;Cette dernière rubrique contient toutes les assertions (vérifications) faites sur le système. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Un test avec une partie "Then" vide est un test inutile !&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;GWT est un format trivial à mettre en place qui peut grandement aider la rédaction de test et mettre en valeur les défauts de conception d'un système. &lt;br&gt;
Toutefois, l'implémentation présentée ici n'est que la simplification du langage "&lt;a href="https://cucumber.io/docs/gherkin/"&gt;Gerkhin&lt;/a&gt;" utilisé par l'outil "&lt;a href="https://cucumber.io/"&gt;Cucumber&lt;/a&gt;".&lt;/p&gt;

&lt;p&gt;Si vous souhaitez en savoir plus sur GWT, je vous invite à lire cet &lt;a href="https://martinfowler.com/bliki/GivenWhenThen.html"&gt;article&lt;/a&gt; de Martin Fowler.&lt;/p&gt;

</description>
      <category>gwt</category>
      <category>cucumber</category>
      <category>test</category>
      <category>qa</category>
    </item>
    <item>
      <title>QA - Définitions et théorie</title>
      <dc:creator>Raphaël Anic-Antic</dc:creator>
      <pubDate>Tue, 17 Oct 2023 18:17:22 +0000</pubDate>
      <link>https://dev.to/rafatic/qa-definitions-et-theorie-7nn</link>
      <guid>https://dev.to/rafatic/qa-definitions-et-theorie-7nn</guid>
      <description>&lt;h2&gt;
  
  
  On dit Assurance ou Contrôle Qualité ?
&lt;/h2&gt;

&lt;p&gt;En réalité, on peut dire les deux. Mais ces deux termes désignent des concepts différents !&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assurance qualité (QA)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;définition&lt;/strong&gt; : méthode visant à empêcher l'apparition d'erreurs et défauts dans un produit afin d'éviter des problèmes lors de sa livraison&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;objectif&lt;/strong&gt; : examiner et modifier les procédés utilisés pour obtenir un produit final&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Contrôle qualité (QC)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;définition&lt;/strong&gt; : processus utilisé pour certifier la qualité d'un produit ou d'un service par rapport à des exigences&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;objectif&lt;/strong&gt; : examiner le produit ou service et vérifier qu'il réponds correctement aux exigences formulées&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En ingénierie logicielle, le contrôle qualité consiste à tester du code (automatiquement ou non) tandis que l'assurance qualité vise à définir les méthodes et procédé utilisés pour limiter le risque de défauts pendant la production du code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;L'assurance qualité est une pratique qui s'inscrit sur l'ensemble de la pipeline de développements. Elle concerne tout les acteurs d'un projet.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Stratégies de tests
&lt;/h2&gt;

&lt;p&gt;Une stratégie de test vise à définir l'objectif d'un test. Il ne faut pas la confondre avec un "type" de test (que nous aborderons plus tard).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tests d'acceptation :&lt;/strong&gt; vérifier le bon comportement d'une fonctionnalité et son respect de la spécification&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tests de non régression :&lt;/strong&gt; vérifier l'absence d'impact d'un nouveau développement sur les fonctionnalités déjà présentes&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note : avec le temps, les tests d'acceptation deviennent des tests de non régression&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Tests de caractérisation :&lt;/strong&gt; caractériser et document le comportement d'une fonctionnalité mal connue.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note : les tests de caractérisation peuvent être utilisés comme des tests de non  régression sur des fonctionnalités non spécifiées ou legacy&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  SUT
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;définition :&lt;/strong&gt; System Under Test. Système affecté par un test&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Objectif :&lt;/strong&gt; Le SUT permet de définir le périmètre d'un test. C'est à dire, l'objectif de ce dernier. Il est généralement préférable d'avoir le périmètre le plus réduit possible afin de faciliter la maintenance du test.&lt;/p&gt;

</description>
      <category>qa</category>
      <category>qc</category>
      <category>tests</category>
      <category>theory</category>
    </item>
    <item>
      <title>QA - Comment rédiger un test utile ?</title>
      <dc:creator>Raphaël Anic-Antic</dc:creator>
      <pubDate>Tue, 17 Oct 2023 17:29:20 +0000</pubDate>
      <link>https://dev.to/rafatic/qa-comment-rediger-un-test-utile--1m0c</link>
      <guid>https://dev.to/rafatic/qa-comment-rediger-un-test-utile--1m0c</guid>
      <description>&lt;p&gt;Dans cet article, nous allons nous intéresser à la valeur des tests automatisés. En effet, chaque test a une valeur et un cout.&lt;/p&gt;

&lt;p&gt;C'est à dire, comment ils permettent de résoudre leurs problèmes métiers. La valeur ajoutée est elle systématique ? En tant que développeurs, comment pouvons nous rédiger les tests les plus utiles possibles ?&lt;/p&gt;

&lt;h2&gt;
  
  
  L'argent ne pousse pas sur les arbres. Les tests non plus
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Chaque test a une valeur et un cout.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Sa valeur est représentée par sa capacité à réduire les risques lors des développements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Son coût est est le temps de travail nécessaire à sa mise en place et à sa maintenance. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Le coût de maintenance ne doit pas être sous-estimé, un test complexe et prompt aux erreurs devra souvent être re-analysé et modifié.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Impact :&lt;/strong&gt; un test qui détecte des bugs à impact fort a plus de valeur qu'un test qui détecte des bugs très mineurs.&lt;/p&gt;

&lt;p&gt;Cela ne veut pas dire qu’il ne faut pas tester les bugs mineurs. Il faut cependant jauger le coût d'un test pour rester rentable.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;NB: les tests manuels sont très onéreux car chaque exécution induit des coûts supplémentaires&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Quels facteurs rendent un test plus ou moins rentable ?
&lt;/h2&gt;

&lt;p&gt;Il existe plusieurs facteurs qui peuvent affecter la rentabilité d'un test.&lt;/p&gt;

&lt;p&gt;L'objectif de cet article est de mettre en lumière les facteurs principaux et de tenter de fournir des solutions permettant de rendre nos tests plus rentables&lt;/p&gt;

&lt;h3&gt;
  
  
  Le diagnostique, c'est pas automatique
&lt;/h3&gt;

&lt;p&gt;En cas d’erreur, le test doit être capable de décrire précisément le bug rencontré. Pour se faire, un test doit se concentrer sur un composant précis et le tester indépendamment.&lt;/p&gt;

&lt;p&gt;Exemple : Dans un formulaire, tester le fonctionnement d’un champ en particulier sans se soucier de la valeur des autres champs (ie. y insérer des cas nominaux).&lt;/p&gt;

&lt;p&gt;Cette notion est appelée le &lt;strong&gt;périmètre&lt;/strong&gt; d'un test. Généralement, on souhaite créer un test avec le **périmètre le plus petit possible". De cette façon, si quelque chose casse, on sait exactement quoi.&lt;/p&gt;

&lt;p&gt;Exemple d'un petit périmètre :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Contexte]
J'ai un service backend qui récupère des montants notes de frais depuis une API externe, calcule le total Hors Taxes des montants et les enregistre en base de données.

Je souhaite rédiger un test automatisé qui vérifie que le calcul de total Hors Taxes est correct.

[Décision]
La valeur de ce test réside dans la vérification du calcul TTC -&amp;gt; HT. 
Vérifier le fonctionnement de l'API et de la BDD n'apportent aucune valeur à mon test. 

Je choisis de les exclure de mon périmètre de test.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Connaissez vous la définition de la folie ?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kkYw9E1l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://64.media.tumblr.com/f9d66acd7afd8208b6ef4d8c657597fd/tumblr_nlfb27Knsv1tqv9ono2_500.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kkYw9E1l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://64.media.tumblr.com/f9d66acd7afd8208b6ef4d8c657597fd/tumblr_nlfb27Knsv1tqv9ono2_500.gif" alt="Definition of insanity Far Cry 3" width="500" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;La folie c'est faire la même chose encore et encore et s'attendre à un résultat différent&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Si vous avez déjà eu un test qui, entre deux exécutions, produit des résultats différents, alors vous êtes familier avec cette définition.&lt;/p&gt;

&lt;p&gt;Il arrive qu'un tests puisse avoir des résultats différents entre plusieurs exécutions. On appelle ses tests &lt;em&gt;"flaky tests"&lt;/em&gt; ("friables" ou "peu fiable" en français).&lt;/p&gt;

&lt;p&gt;Ce type d'irrégularité peut apparaitre lorsque le &lt;strong&gt;périmètre&lt;/strong&gt; du test est trop large (i.e. trop de variables entrent en jeu) ou si le scénario de test n'est pas assez précis.&lt;/p&gt;

&lt;p&gt;Si vous rencontrez ce genre de problèmes, isolez les variables, simplifiez le test voir diviser le en plusieurs&lt;/p&gt;

&lt;h3&gt;
  
  
  Un test n'est rien d'autre qu'une spécification
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jEJ691IV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dcruyy4607vzg7ohqu6c.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jEJ691IV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dcruyy4607vzg7ohqu6c.jpg" alt="tests-specs-same-thing" width="454" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Comme nous avons déjà pu le dire, un test permet de vérifier le bon comportement d'une fonctionnalité.&lt;/p&gt;

&lt;p&gt;Cependant, son usage ne se limite pas là. Il peut aussi servir de documentation pour les équipes de développement. En spécifiant le comportement attendu, il jour aussi le rôle de... spécification.&lt;/p&gt;

&lt;p&gt;Il est possible de faire gagner de la valeur à un test en le traitant comme une spécification. Un test peut paraphraser la spécification fonctionnelle et documenter, en détail, le comportement attendu.&lt;/p&gt;

&lt;h2&gt;
  
  
  Récapitulatif
&lt;/h2&gt;

&lt;p&gt;Maintenant que nous avons abordé les notions théoriques affectant la valeur d'un test, je vous propose un court récapitulatif d'actions et de concepts à garder en tête pendant la rédaction de vos tests.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note : ces instructions sont valables pour des tests automatisés ou manuels&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Caractéristiques d'un "bon" test
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A des instructions claires sur quand et comment l'exécuter&lt;/li&gt;
&lt;li&gt;Spécifie le résultat désiré&lt;/li&gt;
&lt;li&gt;Spécifie les résultats non désirés&lt;/li&gt;
&lt;li&gt;Isole correctement la fonctionnalité testée (on sait d’où vient le bug)&lt;/li&gt;
&lt;li&gt;Est basé sur les spécifications et non sur l’implémentation&lt;/li&gt;
&lt;li&gt;Documente clairement son fonctionnement et son objectif. Si une fonctionnalité change, les tests liés doivent être modifiables simplement&lt;/li&gt;
&lt;li&gt;Vérifie les comportements courants en premier&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Caractéristiques d'un "mauvais" test
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;N’est pas documenté ou ne peut être exécuté que par quelqu’un familier avec la fonctionnalité testée&lt;/li&gt;
&lt;li&gt;Donne des résultats non reproductibles&lt;/li&gt;
&lt;li&gt;Ne couvre que les cas nominaux&lt;/li&gt;
&lt;li&gt;Utilise une méthodologie différente du reste du catalogue de test&lt;/li&gt;
&lt;li&gt;Nécessite des modifications de l’environnement qui ne sont pas réalistes (~ ne correspondent pas à la production)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>qa</category>
      <category>tests</category>
    </item>
  </channel>
</rss>
