<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://kensa.dev/blog</id>
    <title>Kensa Blog</title>
    <updated>2026-04-08T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://kensa.dev/blog"/>
    <subtitle>Kensa Blog</subtitle>
    <icon>https://kensa.dev/img/Logo.svg</icon>
    <entry>
        <title type="html"><![CDATA[Introducing Kensa: BDD for Kotlin and Java Without the Gherkin Tax]]></title>
        <id>https://kensa.dev/blog/introducing-kensa</id>
        <link href="https://kensa.dev/blog/introducing-kensa"/>
        <updated>2026-04-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[If you've ever set up Cucumber on a JVM project, you know the overhead: feature files, step definitions, the glue code that ties them together, and the constant friction of keeping all three in sync as your codebase evolves. The promise — shared, readable specifications — rarely survives contact with a real team.]]></summary>
        <content type="html"><![CDATA[<p>If you've ever set up Cucumber on a JVM project, you know the overhead: feature files, step definitions, the glue code that ties them together, and the constant friction of keeping all three in sync as your codebase evolves. The promise — shared, readable specifications — rarely survives contact with a real team.</p>
<p><strong>Kensa takes a different approach.</strong> Write your Given-When-Then tests directly in Kotlin or Java. No Gherkin. No step definitions. No separate files to maintain.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-it-works">How It Works<a href="https://kensa.dev/blog/introducing-kensa#how-it-works" class="hash-link" aria-label="Direct link to How It Works" title="Direct link to How It Works" translate="no">​</a></h2>
<p>Kensa parses your test source code at runtime, extracts the sentence structure of each test method, and substitutes actual captured values for variable names. The result is living HTML documentation generated directly from your tests — not from a separate spec file that may or may not reflect what your code actually does.</p>
<p>Here's a test from the <a href="https://github.com/kensa-dev/clearwave-kensa-example" target="_blank" rel="noopener noreferrer" class="">Clearwave example</a> — a fictional telecoms service that checks broadband feasibility across two supplier networks:</p>
<div class="language-kotlin codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-kotlin codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token annotation builtin">@Test</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">fun</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">`address is serviceable by both suppliers`</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">given</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">bothSuppliersAreServiceable</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">whenever</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">aFeasibilityCheckIsRequestedForTheServiceAddress</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">theFeasibilityResult</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">shouldReturnServiceableResultWith</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        profileCount </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        fastestDownloadSpeed </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> fixtures</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">voiceDownloadSpeed</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        fastestSupplier </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> fixtures</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">voiceSupplier</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>The test <em>is</em> the specification. The report shows the test sentences with real values substituted in — <code>fastestDownloadSpeed</code> and <code>fastestSupplier</code> in the report reflect what actually ran, captured from the fixture values.</p>
<div class="wrapper_XeOc"><button class="btn_NZut" aria-label="View full-size: Kensa report showing the feasibility test with sequence diagram"><img src="https://kensa.dev/img/clearwave-screen-1.png" alt="Kensa report showing the feasibility test with sequence diagram" class="img_DTUR"></button></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-you-get">What You Get<a href="https://kensa.dev/blog/introducing-kensa#what-you-get" class="hash-link" aria-label="Direct link to What You Get" title="Direct link to What You Get" translate="no">​</a></h2>
<ul>
<li class=""><strong>HTML reports</strong> with the test sentences, captured state, and a full interaction log</li>
<li class=""><strong>Sequence diagrams</strong> auto-generated from the interactions your tests record</li>
<li class=""><strong>Inspectable payloads</strong> — click any interaction to see the full request/response</li>
</ul>
<div class="wrapper_XeOc"><button class="btn_NZut" aria-label="View full-size: JSON interaction detail showing the feasibility check response"><img src="https://kensa.dev/img/clearwave-screen-2.png" alt="JSON interaction detail showing the feasibility check response" class="img_DTUR"></button></div>
<ul>
<li class=""><strong>Framework integration</strong> — JUnit 5 &amp; 6, Kotest, and TestNG are all supported</li>
<li class=""><strong>Assertion library flexibility</strong> — Hamcrest, AssertJ, Kotest assertions, or HamKrest</li>
<li class=""><strong>A Kotlin compiler plugin</strong> for <code>@RenderedValue</code> and <code>@ExpandableSentence</code> — capture values in reports without boilerplate</li>
<li class=""><strong>An IntelliJ plugin</strong> for navigating reports from the IDE</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="getting-started">Getting Started<a href="https://kensa.dev/blog/introducing-kensa#getting-started" class="hash-link" aria-label="Direct link to Getting Started" title="Direct link to Getting Started" translate="no">​</a></h2>
<p>Add the dependency and extend <code>KensaTest</code>:</p>
<div class="language-kotlin codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-kotlin codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// build.gradle.kts</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">testImplementation</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-literal singleline string" style="color:#e3116c">"dev.kensa:kensa-junit:0.6.6"</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>The <a class="" href="https://kensa.dev/docs/quickstart/kotlin-quickstart">Kotlin Quickstart</a> walks through a complete example in a few minutes.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="see-it-in-action">See It In Action<a href="https://kensa.dev/blog/introducing-kensa#see-it-in-action" class="hash-link" aria-label="Direct link to See It In Action" title="Direct link to See It In Action" translate="no">​</a></h2>
<p>The <a href="https://github.com/kensa-dev/clearwave-kensa-example" target="_blank" rel="noopener noreferrer" class="">Clearwave example repo</a> is a self-contained project showing a more complete scenario — async order processing across multiple suppliers, with sequence diagrams auto-generated from the interaction captures. You can browse the <a href="https://kensa-dev.github.io/clearwave-kensa-example" target="_blank" rel="noopener noreferrer" class="">live Kensa report</a> to see what the output looks like.</p>
<p>Kensa itself is open source on <a href="https://github.com/kensa-dev/kensa" target="_blank" rel="noopener noreferrer" class="">GitHub</a>. Feedback and contributions welcome.</p>]]></content>
        <author>
            <name>Paul Brooks</name>
            <uri>https://github.com/kensa-dev</uri>
        </author>
        <category label="kotlin" term="kotlin"/>
        <category label="java" term="java"/>
        <category label="bdd" term="bdd"/>
        <category label="testing" term="testing"/>
        <category label="junit" term="junit"/>
        <category label="kotest" term="kotest"/>
    </entry>
</feed>