<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Invariants on Ocarina — précis</title>
    <link>https://mojo-molotov.github.io/from-ocarina-to-igor/fr/tags/invariants/</link>
    <description>Recent content in Invariants on Ocarina — précis</description>
    <generator>Hugo</generator>
    <language>fr-FR</language>
    <lastBuildDate>Thu, 28 May 2026 21:02:53 +0200</lastBuildDate>
    <atom:link href="https://mojo-molotov.github.io/from-ocarina-to-igor/fr/tags/invariants/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Chapitre 02.04 — Invariants</title>
      <link>https://mojo-molotov.github.io/from-ocarina-to-igor/fr/02-ocarina/04-invariants/</link>
      <pubDate>Wed, 20 May 2026 00:00:00 +0000</pubDate>
      <guid>https://mojo-molotov.github.io/from-ocarina-to-igor/fr/02-ocarina/04-invariants/</guid>
      <description>&lt;h1 id=&#34;chapitre-0204invariants&#34;&gt;Chapitre 02.04 — Invariants&lt;a class=&#34;anchor&#34; href=&#34;#chapitre-0204invariants&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;blockquote class=&#39;book-hint &#39;&gt;&#xA;&lt;p&gt;Sous-DSL d&amp;rsquo;Ocarina dédié à l&amp;rsquo;expression d&amp;rsquo;invariants typés et composables. Utilisé partout : par la CLI, par les POMs, par les &lt;code&gt;custom_invariants/testing/&lt;/code&gt; qui valident la cohérence des suites avant exécution.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&lt;h2 id=&#34;plan&#34;&gt;Plan&lt;a class=&#34;anchor&#34; href=&#34;#plan&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th style=&#34;text-align: center&#34;&gt;#&lt;/th&gt;&#xA;          &lt;th&gt;Fichier&lt;/th&gt;&#xA;          &lt;th&gt;Sujet&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;01&lt;/td&gt;&#xA;          &lt;td&gt;&lt;a href=&#34;https://mojo-molotov.github.io/from-ocarina-to-igor/fr/02-ocarina/04-invariants/01-validate-flow/&#34;&gt;&lt;code&gt;01-validate-flow.md&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Le flot complet &lt;code&gt;validate(value) → assert_that → execute → raise_if_invalid&lt;/code&gt; + la classe &lt;code&gt;_ValidationChain&lt;/code&gt;.&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;02&lt;/td&gt;&#xA;          &lt;td&gt;&lt;a href=&#34;https://mojo-molotov.github.io/from-ocarina-to-igor/fr/02-ocarina/04-invariants/02-assertions/&#34;&gt;&lt;code&gt;02-assertions.md&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Catalogue des assertions builtin (&lt;code&gt;is_str&lt;/code&gt;, &lt;code&gt;is_email&lt;/code&gt;, &lt;code&gt;is_positive&lt;/code&gt;, &lt;code&gt;is_in&lt;/code&gt;, &lt;code&gt;has_unique_elements&lt;/code&gt;, &lt;code&gt;each&lt;/code&gt;, &lt;code&gt;is_valid_filename&lt;/code&gt;, …).&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;03&lt;/td&gt;&#xA;          &lt;td&gt;&lt;a href=&#34;https://mojo-molotov.github.io/from-ocarina-to-igor/fr/02-ocarina/04-invariants/03-otherwise-any-of/&#34;&gt;&lt;code&gt;03-otherwise-any-of.md&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;.otherwise(...)&lt;/code&gt; et la combinaison OR via &lt;code&gt;_any_of&lt;/code&gt;.&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;04&lt;/td&gt;&#xA;          &lt;td&gt;&lt;a href=&#34;https://mojo-molotov.github.io/from-ocarina-to-igor/fr/02-ocarina/04-invariants/04-then-chain-of-validations/&#34;&gt;&lt;code&gt;04-then-chain-of-validations.md&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;.then(new_value)&lt;/code&gt; et &lt;code&gt;chain_validations(...)&lt;/code&gt; pour la composition.&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;05&lt;/td&gt;&#xA;          &lt;td&gt;&lt;a href=&#34;https://mojo-molotov.github.io/from-ocarina-to-igor/fr/02-ocarina/04-invariants/05-business-vs-framework-validator/&#34;&gt;&lt;code&gt;05-business-vs-framework-validator.md&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;BusinessInvariantValidator&lt;/code&gt; vs &lt;code&gt;FrameworkInvariantValidator&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;06&lt;/td&gt;&#xA;          &lt;td&gt;&lt;a href=&#34;https://mojo-molotov.github.io/from-ocarina-to-igor/fr/02-ocarina/04-invariants/06-invariant-errors/&#34;&gt;&lt;code&gt;06-invariant-errors.md&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;InvariantViolationError&lt;/code&gt;, &lt;code&gt;DuplicatesError&lt;/code&gt;, &lt;code&gt;AggregateInvariantViolationError&lt;/code&gt;.&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h2 id=&#34;le-pourquoi-du-dsl-dinvariants&#34;&gt;Le pourquoi du DSL d&amp;rsquo;invariants&lt;a class=&#34;anchor&#34; href=&#34;#le-pourquoi-du-dsl-dinvariants&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;Garde-fou avant exécution.&lt;/strong&gt; &lt;code&gt;TestSuite.__init__&lt;/code&gt; valide &lt;em&gt;avant&lt;/em&gt; de lancer quoi que ce soit que les noms / IDs des tests sont uniques, que &lt;code&gt;max_workers &amp;gt;= 1&lt;/code&gt;, etc.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Validation CLI.&lt;/strong&gt; Chaque flag a son &lt;code&gt;validate=lambda chain: chain.assert_that(...)&lt;/code&gt; dans le &lt;code&gt;CliStore&lt;/code&gt;. Les erreurs s&amp;rsquo;agrègent et sortent en un seul message d&amp;rsquo;erreur.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Validation côté POM.&lt;/strong&gt; Les actions de POM peuvent valider leurs paramètres (« &lt;em&gt;&lt;code&gt;retries&lt;/code&gt; doit être positif&lt;/em&gt; ») via &lt;code&gt;validate(retries, name=&amp;quot;retries&amp;quot;).assert_that(is_positive).execute().raise_if_invalid()&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Le Holy Book le résume :&lt;/p&gt;</description>
    </item>
    <item>
      <title>Chapitre 02.05 — Orchestration</title>
      <link>https://mojo-molotov.github.io/from-ocarina-to-igor/fr/02-ocarina/05-orchestration/</link>
      <pubDate>Wed, 20 May 2026 00:00:00 +0000</pubDate>
      <guid>https://mojo-molotov.github.io/from-ocarina-to-igor/fr/02-ocarina/05-orchestration/</guid>
      <description>&lt;h1 id=&#34;chapitre-0205orchestration&#34;&gt;Chapitre 02.05 — Orchestration&lt;a class=&#34;anchor&#34; href=&#34;#chapitre-0205orchestration&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;blockquote class=&#39;book-hint &#39;&gt;&#xA;&lt;p&gt;Chaîne &lt;code&gt;Test → TestSuite → TestCampaign → TestCycle&lt;/code&gt; : comment chaque niveau s&amp;rsquo;articule, qui gère la parallélisation, qui gère les rejeux, qui décide du &lt;em&gt;skip&lt;/em&gt;, et où vivent les invariants pré-exécution.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&lt;h2 id=&#34;plan&#34;&gt;Plan&lt;a class=&#34;anchor&#34; href=&#34;#plan&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th style=&#34;text-align: center&#34;&gt;#&lt;/th&gt;&#xA;          &lt;th&gt;Fichier&lt;/th&gt;&#xA;          &lt;th&gt;Sujet&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;01&lt;/td&gt;&#xA;          &lt;td&gt;&lt;a href=&#34;https://mojo-molotov.github.io/from-ocarina-to-igor/fr/02-ocarina/05-orchestration/01-test/&#34;&gt;&lt;code&gt;01-test.md&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#xA;          &lt;td&gt;La classe &lt;code&gt;Test[Driver]&lt;/code&gt; — &lt;code&gt;spawn&lt;/code&gt;, fragments pre/post, skip.&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;02&lt;/td&gt;&#xA;          &lt;td&gt;&lt;a href=&#34;https://mojo-molotov.github.io/from-ocarina-to-igor/fr/02-ocarina/05-orchestration/02-test-executor/&#34;&gt;&lt;code&gt;02-test-executor.md&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;TestExecutor&lt;/code&gt; — exécution d&amp;rsquo;&lt;strong&gt;une&lt;/strong&gt; tentative, ordre : setup → watchers.start → chain → watchers.stop → teardown.&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;03&lt;/td&gt;&#xA;          &lt;td&gt;&lt;a href=&#34;https://mojo-molotov.github.io/from-ocarina-to-igor/fr/02-ocarina/05-orchestration/03-test-flow-retries/&#34;&gt;&lt;code&gt;03-test-flow-retries.md&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;TestFlow&lt;/code&gt; — boucle de rejeu (1+max_retries), backoff linéaire, gestion des setup-failures.&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;04&lt;/td&gt;&#xA;          &lt;td&gt;&lt;a href=&#34;https://mojo-molotov.github.io/from-ocarina-to-igor/fr/02-ocarina/05-orchestration/04-test-suite/&#34;&gt;&lt;code&gt;04-test-suite.md&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;TestSuite&lt;/code&gt; — parallélisation avec &lt;code&gt;ThreadPoolExecutor&lt;/code&gt;, filtrage IDs, garde-fous.&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;05&lt;/td&gt;&#xA;          &lt;td&gt;&lt;a href=&#34;https://mojo-molotov.github.io/from-ocarina-to-igor/fr/02-ocarina/05-orchestration/05-saturation/&#34;&gt;&lt;code&gt;05-saturation.md&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Saturation des workers : clonage aléatoire &lt;code&gt;[COPY N]&lt;/code&gt;. Pourquoi et comment.&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;06&lt;/td&gt;&#xA;          &lt;td&gt;&lt;a href=&#34;https://mojo-molotov.github.io/from-ocarina-to-igor/fr/02-ocarina/05-orchestration/06-test-campaign/&#34;&gt;&lt;code&gt;06-test-campaign.md&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;TestCampaign&lt;/code&gt; — séquence de suites, &lt;code&gt;campaign_has_failed&lt;/code&gt;.&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;07&lt;/td&gt;&#xA;          &lt;td&gt;&lt;a href=&#34;https://mojo-molotov.github.io/from-ocarina-to-igor/fr/02-ocarina/05-orchestration/07-test-cycle-modes/&#34;&gt;&lt;code&gt;07-test-cycle-modes.md&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;TestCycle&lt;/code&gt; — smoke + main, modes &lt;code&gt;fail-fast&lt;/code&gt; vs &lt;code&gt;wait-for-all&lt;/code&gt;, &lt;code&gt;has_test_cycle_failed&lt;/code&gt;.&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;08&lt;/td&gt;&#xA;          &lt;td&gt;&lt;a href=&#34;https://mojo-molotov.github.io/from-ocarina-to-igor/fr/02-ocarina/05-orchestration/08-filter-tests-by-ids/&#34;&gt;&lt;code&gt;08-filter-tests-by-ids.md&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;filter_tests_by_ids&lt;/code&gt; — &lt;code&gt;--only&lt;/code&gt;/&lt;code&gt;--exclude&lt;/code&gt;, mutex, ignore les unknown IDs.&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h2 id=&#34;schéma&#34;&gt;Schéma&lt;a class=&#34;anchor&#34; href=&#34;#sch%c3%a9ma&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;            ┌────────────────────────────────────────────────┐&#xA;            │                  TestCycle                     │&#xA;            │                                                │&#xA;            │  ┌──────────────────────────────────────────┐  │&#xA;            │  │ smoke_tests_campaigns                    │  │ ◄── 1er, gate&#xA;            │  │  └─ TestCampaign                         │  │     mode : fail-fast |&#xA;            │  │      └─ TestSuite                        │  │            wait-for-all&#xA;            │  │          └─ Test                         │  │&#xA;            │  └──────────────────────────────────────────┘  │&#xA;            │                                                │&#xA;            │  ┌──────────────────────────────────────────┐  │&#xA;            │  │ campaigns (main)                         │  │ ◄── skippées si&#xA;            │  │  └─ TestCampaign                         │  │     un smoke fail&#xA;            │  │      └─ TestSuite                        │  │&#xA;            │  │          └─ Test                         │  │&#xA;            │  └──────────────────────────────────────────┘  │&#xA;            └────────────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;qui-fait-quoi&#34;&gt;Qui fait quoi ?&lt;a class=&#34;anchor&#34; href=&#34;#qui-fait-quoi&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;Niveau&lt;/th&gt;&#xA;          &lt;th&gt;Responsabilité unique&lt;/th&gt;&#xA;          &lt;th&gt;Concurrence&lt;/th&gt;&#xA;          &lt;th&gt;Hors périmètre&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;Test&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Métadonnées + &lt;code&gt;spawn(driver, logger)&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;aucune&lt;/td&gt;&#xA;          &lt;td&gt;exécution&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;TestExecutor&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Une &lt;strong&gt;tentative&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;aucune&lt;/td&gt;&#xA;          &lt;td&gt;rejeu, acquisition de driver&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;TestFlow&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Boucle de &lt;strong&gt;rejeu&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;aucune&lt;/td&gt;&#xA;          &lt;td&gt;parallélisation, agrégation&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;TestSuite&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Parallélisation + saturation + filtrage IDs&lt;/td&gt;&#xA;          &lt;td&gt;&lt;strong&gt;N threads&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;séquence inter-suites&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;TestCampaign&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Séquence de suites&lt;/td&gt;&#xA;          &lt;td&gt;suite-level&lt;/td&gt;&#xA;          &lt;td&gt;smoke vs main&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;TestCycle&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;Smoke + main + mode&lt;/td&gt;&#xA;          &lt;td&gt;campaign-level&lt;/td&gt;&#xA;          &lt;td&gt;bootstrap / plugins post-exec&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;Cette séparation stricte est &lt;strong&gt;délibérée&lt;/strong&gt; : &lt;code&gt;TestExecutor&lt;/code&gt; ne sait rien des retries, &lt;code&gt;TestFlow&lt;/code&gt; ne sait rien de la concurrence, &lt;code&gt;TestSuite&lt;/code&gt; ne sait rien de l&amp;rsquo;agrégation campaign-level. Chaque classe a un seul axe de responsabilité.&lt;/p&gt;</description>
    </item>
    <item>
      <title>04.06 — Property-based testing (hypothesis)</title>
      <link>https://mojo-molotov.github.io/from-ocarina-to-igor/fr/04-internal-tests/06-hypothesis-properties/</link>
      <pubDate>Wed, 20 May 2026 00:00:00 +0000</pubDate>
      <guid>https://mojo-molotov.github.io/from-ocarina-to-igor/fr/04-internal-tests/06-hypothesis-properties/</guid>
      <description>&lt;h1 id=&#34;0406property-based-testing-hypothesis&#34;&gt;04.06 — Property-based testing (&lt;code&gt;hypothesis&lt;/code&gt;)&lt;a class=&#34;anchor&#34; href=&#34;#0406property-based-testing-hypothesis&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h1&gt;&#xA;&lt;blockquote class=&#39;book-hint &#39;&gt;&#xA;&lt;p&gt;Un seul fichier (&lt;code&gt;test_invariants_properties.py&lt;/code&gt;), mais le pattern est intéressant : on &lt;strong&gt;génère&lt;/strong&gt; des inputs et on vérifie des &lt;strong&gt;propriétés universelles&lt;/strong&gt; des prédicats d&amp;rsquo;invariants.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&lt;h2 id=&#34;le-concept&#34;&gt;Le concept&lt;a class=&#34;anchor&#34; href=&#34;#le-concept&#34; data-pagefind-ignore=&#34;all&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;hypothesis&lt;/code&gt; génère automatiquement des &lt;em&gt;cas de test&lt;/em&gt; qui satisfont des contraintes données, puis vérifie qu&amp;rsquo;une propriété est vraie pour tous les cas générés. En cas d&amp;rsquo;échec, &lt;em&gt;hypothesis&lt;/em&gt; fait du &lt;strong&gt;shrinking&lt;/strong&gt; pour trouver le &lt;strong&gt;plus petit contre-exemple&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff79c6&#34;&gt;from&lt;/span&gt; hypothesis &lt;span style=&#34;color:#ff79c6&#34;&gt;import&lt;/span&gt; given, strategies &lt;span style=&#34;color:#ff79c6&#34;&gt;as&lt;/span&gt; st&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@given(st&lt;span style=&#34;color:#ff79c6&#34;&gt;.&lt;/span&gt;integers())&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff79c6&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#50fa7b&#34;&gt;test_is_positive_passes_on_positive&lt;/span&gt;(value):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff79c6&#34;&gt;if&lt;/span&gt; value &lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color:#bd93f9&#34;&gt;0&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        is_positive(value)             &lt;span style=&#34;color:#6272a4&#34;&gt;# ne doit pas lever&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff79c6&#34;&gt;else&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#ff79c6&#34;&gt;with&lt;/span&gt; pytest&lt;span style=&#34;color:#ff79c6&#34;&gt;.&lt;/span&gt;raises(InvariantViolationError):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            is_positive(value)         &lt;span style=&#34;color:#6272a4&#34;&gt;# doit lever&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;→ &lt;code&gt;hypothesis&lt;/code&gt; génère des entiers (typiquement 100 par défaut), vérifie la propriété pour chacun. Si une exception &lt;em&gt;inattendue&lt;/em&gt; surgit, c&amp;rsquo;est un fail. Le shrinker trouve le plus petit cas qui fail (&lt;code&gt;0&lt;/code&gt; ? &lt;code&gt;-1&lt;/code&gt; ? &lt;code&gt;MIN_INT&lt;/code&gt; ?).&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
