<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Testing on Sven Ruppert</title><link>https://svenruppert.com/tags/testing/</link><description>Sven Ruppert — Java Veteran, Speaker, Trainer &amp; Bushcrafter. Articles, talks, workshops and videos on Core Java, Cybersecurity, Vaadin and Developer Relations.</description><generator>Hugo</generator><language>en</language><managingEditor>sven.ruppert@gmail.com (Sven Ruppert)</managingEditor><webMaster>sven.ruppert@gmail.com (Sven Ruppert)</webMaster><copyright>© 2026 Sven Ruppert</copyright><atom:link href="https://svenruppert.com/tags/testing/index.xml" rel="self" type="application/rss+xml"/><image><url>https://svenruppert.com/img/sven-ruppert.jpg</url><title>Sven Ruppert</title><link>https://svenruppert.com/tags/testing/</link></image><lastBuildDate>Fri, 12 Jun 2026 00:00:00 +0000</lastBuildDate><item><title>CalDAV Testbench</title><link>https://svenruppert.com/projects/caldav-testbench/</link><pubDate>Fri, 12 Jun 2026 00:00:00 +0000</pubDate><author>sven.ruppert@gmail.com (Sven Ruppert)</author><dc:creator>Sven Ruppert</dc:creator><guid isPermaLink="true">https://svenruppert.com/projects/caldav-testbench/</guid><description>A deliberately small in-memory CalDAV server for test-driven development. Embed it in JUnit tests when you need a predictable CalDAV endpoint without the operational noise of a real calendar server.</description><content:encoded>&lt;![CDATA[<p>A small, embeddable<strong>CalDAV server</strong> built for one purpose: making
calendar-client tests<strong>deterministic, fast and inspectable</strong>. When you need
a real CalDAV endpoint to drive your TDD cycle but a full external calendar
server would add too much noise, this is what you reach for.</p><h2 id="what-it-implements">What it implements</h2><p>A focused subset of<a href="https://datatracker.ietf.org/doc/html/rfc4791">RFC 4791</a>:</p><ul><li><code>PUT</code>,<code>GET</code>,<code>DELETE</code> for calendar resources</li><li><strong>ETag-based conditional writes</strong> with<code>If-Match</code> /<code>If-None-Match</code></li><li><code>PROPFIND</code> for collection and resource property discovery</li><li><code>REPORT</code> with<strong><code>calendar-multiget</code></strong></li><li><code>REPORT</code> with<strong><code>calendar-query</code></strong>, including time-range filtering</li><li>basic<strong>recurrence expansion</strong> for query matching</li><li><strong>XML hardening</strong>, request body limits, structured XML error responses</li></ul><p>It does<strong>not</strong> try to be a complete CalDAV server. Intentionally unsupported
behaviour should make your test contracts visible — that&rsquo;s the whole point.</p><h2 id="why-a-separate-testbench">Why a separate testbench?</h2><p>Tests that hit a shared calendar server are flaky by construction: state
bleeds between runs, schemas evolve, networks twitch. Tests that mock the
HTTP layer miss the actual protocol semantics — exactly where CalDAV bugs
hide.</p><p>CalDAV Testbench sits in the middle:<strong>real HTTP, real CalDAV semantics,
in-memory state</strong>. The server boots on an OS-assigned port, lives for the
test&rsquo;s lifetime, and goes away clean.</p><h2 id="usage-in-junit">Usage in JUnit</h2><div class="code-wrap"><div class="code-wrap__bar"><span class="code-wrap__lang">xml</span><button type="button" class="code-wrap__copy" aria-label="Copy code">Copy</button></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="nt">&lt;dependency&gt;</span></span></span><span class="line"><span class="cl"><span class="nt">&lt;groupId&gt;</span>com.svenruppert<span class="nt">&lt;/groupId&gt;</span></span></span><span class="line"><span class="cl"><span class="nt">&lt;artifactId&gt;</span>caldav-testbench<span class="nt">&lt;/artifactId&gt;</span></span></span><span class="line"><span class="cl"><span class="nt">&lt;version&gt;</span>00.10.00<span class="nt">&lt;/version&gt;</span></span></span><span class="line"><span class="cl"><span class="nt">&lt;scope&gt;</span>test<span class="nt">&lt;/scope&gt;</span></span></span><span class="line"><span class="cl"><span class="nt">&lt;/dependency&gt;</span></span></span><span class="line"><span class="cl"><span class="nt">&lt;dependency&gt;</span></span></span><span class="line"><span class="cl"><span class="nt">&lt;groupId&gt;</span>com.svenruppert<span class="nt">&lt;/groupId&gt;</span></span></span><span class="line"><span class="cl"><span class="nt">&lt;artifactId&gt;</span>caldav-testbench<span class="nt">&lt;/artifactId&gt;</span></span></span><span class="line"><span class="cl"><span class="nt">&lt;version&gt;</span>00.10.00<span class="nt">&lt;/version&gt;</span></span></span><span class="line"><span class="cl"><span class="nt">&lt;classifier&gt;</span>tests<span class="nt">&lt;/classifier&gt;</span></span></span><span class="line"><span class="cl"><span class="nt">&lt;scope&gt;</span>test<span class="nt">&lt;/scope&gt;</span></span></span><span class="line"><span class="cl"><span class="nt">&lt;/dependency&gt;</span></span></span></code></pre></div></div><p>The test-jar adds<code>CalDavExtension</code> — a JUnit Jupiter extension that
manages server lifecycle.</p><div class="code-wrap"><div class="code-wrap__bar"><span class="code-wrap__lang">java</span><button type="button" class="code-wrap__copy" aria-label="Copy code">Copy</button></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="nd">@ExtendWith</span><span class="p">(</span><span class="n">CalDavExtension</span><span class="p">.</span><span class="na">class</span><span class="p">)</span><span class="w"/></span></span><span class="line"><span class="cl"><span class="kd">class</span><span class="nc">MyCalendarClientTest</span><span class="w"/><span class="p">{</span><span class="w"/></span></span><span class="line"><span class="cl"><span class="w"/><span class="nd">@Test</span><span class="w"/></span></span><span class="line"><span class="cl"><span class="w"/><span class="kt">void</span><span class="w"/><span class="nf">uploadsAndFetchesEvent</span><span class="p">(</span><span class="n">CalDavServer</span><span class="w"/><span class="n">server</span><span class="p">)</span><span class="w"/><span class="p">{</span><span class="w"/></span></span><span class="line"><span class="cl"><span class="w"/><span class="kd">var</span><span class="w"/><span class="n">url</span><span class="w"/><span class="o">=</span><span class="w"/><span class="n">server</span><span class="p">.</span><span class="na">collectionUrl</span><span class="p">(</span><span class="s">"svenr"</span><span class="p">);</span><span class="w"/></span></span><span class="line"><span class="cl"><span class="w"/><span class="c1">// drive your CalDAV client against this URL...</span><span class="w"/></span></span><span class="line"><span class="cl"><span class="w"/><span class="p">}</span><span class="w"/></span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><h2 id="typical-use-cases">Typical use cases</h2><ul><li><strong>TDD a calendar client</strong> — write the test, then implement the request</li><li><strong>Validate sync code</strong> against known server behaviour (ETag races, etc.)</li><li><strong>Verify request generation</strong> for the full CalDAV verb set</li><li><strong>Reproduce edge cases</strong> without depending on a shared external service</li><li>Keep<strong>test fixtures close to the code that uses them</strong></li></ul><h2 id="tech-stack">Tech stack</h2><ul><li><strong>JDK 26</strong> built-in<code>com.sun.net.httpserver.HttpServer</code> (no Jetty, no Netty)</li><li><strong>Biweekly</strong> for iCalendar parsing</li><li><strong>In-memory store</strong> by default;<code>CalendarStore</code> is a documented extension point</li><li>Built and tested with<strong>Maven 4</strong> via wrapper</li></ul><p>A young project (June 2026) that came out of needing exactly this for
other calendar work — not yet at 1.0, but actively used.</p>
]]></content:encoded></item></channel></rss>