<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://adamski.pro/feed.xml" rel="self" type="application/atom+xml" /><link href="https://adamski.pro/" rel="alternate" type="text/html" /><updated>2026-01-26T19:52:32+00:00</updated><id>https://adamski.pro/feed.xml</id><title type="html">adamski.pr()</title><subtitle>adamski .pr()active .pr()grammer μblog</subtitle><entry><title type="html">Wzorzec ObjectMother</title><link href="https://adamski.pro/2023/09/10/object-mother.html" rel="alternate" type="text/html" title="Wzorzec ObjectMother" /><published>2023-09-10T00:00:00+00:00</published><updated>2023-09-10T00:00:00+00:00</updated><id>https://adamski.pro/2023/09/10/object-mother</id><content type="html" xml:base="https://adamski.pro/2023/09/10/object-mother.html"><![CDATA[<h1 id="wzorzec-objectmother">Wzorzec ObjectMother</h1>

<h2 id="wprowadzenie">Wprowadzenie</h2>

<p>Wzorzec projektowy ObjectMother to technika używana w testach jednostkowych, która pomaga w generowaniu obiektów
testowych. W tym wpisie przedstawię, jak można zastosować ten wzorzec w języku Kotlin.</p>

<h2 id="zalety">Zalety</h2>

<ol>
  <li><strong>Czytelność kodu</strong>: Dzięki scentralizowaniu generowania testowych obiektów kod jest bardziej czytelny.</li>
  <li><strong>Łatwość aktualizacji</strong>: Jeśli obiekty zmieniają się, wystarczy zmienić je w jednym miejscu.</li>
  <li><strong>Eliminacja duplikacji kodu</strong>: Unikanie wielokrotnego tworzenia tych samych obiektów w różnych testach.</li>
</ol>

<h2 id="wady">Wady</h2>

<ol>
  <li><strong>Złożoność</strong>: Może wprowadzić dodatkową złożoność, jeśli obiekty są bardzo rozbudowane.</li>
  <li><strong>Naruszenie izolacji testów</strong>: Ryzyko, że zmiana w ObjectMother wpłynie na wiele testów naraz.</li>
</ol>

<h2 id="stosowalność">Stosowalność</h2>

<p>Wzorzec najlepiej sprawdza się w dużych projektach z wieloma testami, które używają podobnych obiektów.</p>

<h2 id="przykład">Przykład</h2>

<h3 id="obiekty-używane-w-przykładzie">Obiekty używane w przykładzie</h3>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">data class</span> <span class="nc">Customer</span><span class="p">(</span><span class="kd">val</span> <span class="py">id</span><span class="p">:</span> <span class="nc">Int</span><span class="p">,</span> <span class="kd">val</span> <span class="py">name</span><span class="p">:</span> <span class="nc">String</span><span class="p">,</span> <span class="kd">val</span> <span class="py">email</span><span class="p">:</span> <span class="nc">String</span><span class="p">)</span>
<span class="kd">data class</span> <span class="nc">Product</span><span class="p">(</span><span class="kd">val</span> <span class="py">id</span><span class="p">:</span> <span class="nc">Int</span><span class="p">,</span> <span class="kd">val</span> <span class="py">name</span><span class="p">:</span> <span class="nc">String</span><span class="p">,</span> <span class="kd">val</span> <span class="py">price</span><span class="p">:</span> <span class="nc">Double</span><span class="p">)</span>
<span class="kd">data class</span> <span class="nc">Order</span><span class="p">(</span><span class="kd">val</span> <span class="py">id</span><span class="p">:</span> <span class="nc">Int</span><span class="p">,</span> <span class="kd">val</span> <span class="py">customer</span><span class="p">:</span> <span class="nc">Customer</span><span class="p">,</span> <span class="kd">val</span> <span class="py">products</span><span class="p">:</span> <span class="nc">List</span><span class="p">&lt;</span><span class="nc">Product</span><span class="p">&gt;)</span>
</code></pre></div></div>

<p><a href="https://github.com/akrystian/object-mother/blob/main/src/main/kotlin/pro/adamski/objectMother/Clases.kt">Pobierz kod na GitHub</a></p>

<h3 id="objectmother-w-kotlinie">ObjectMother w Kotlinie</h3>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="nn">pro.adamski.objectMother</span>

<span class="k">import</span> <span class="nn">kotlin.random.Random</span>

<span class="kd">object</span> <span class="nc">ObjectMother</span> <span class="p">{</span>
    <span class="k">fun</span> <span class="nf">customer</span><span class="p">(</span>
        <span class="n">id</span><span class="p">:</span> <span class="nc">Int</span> <span class="p">=</span> <span class="nc">Random</span><span class="p">.</span><span class="nf">nextInt</span><span class="p">(),</span>
        <span class="n">name</span><span class="p">:</span> <span class="nc">String</span> <span class="p">=</span> <span class="s">"John Doe${Random.nextInt()}"</span><span class="p">,</span>
        <span class="n">email</span><span class="p">:</span> <span class="nc">String</span> <span class="p">=</span> <span class="s">"info-${Random.nextInt()}@example.com"</span>
    <span class="p">):</span> <span class="nc">Customer</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nc">Customer</span><span class="p">(</span><span class="n">id</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">email</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="k">fun</span> <span class="nf">product</span><span class="p">(</span>
        <span class="n">id</span><span class="p">:</span> <span class="nc">Int</span> <span class="p">=</span> <span class="nc">Random</span><span class="p">.</span><span class="nf">nextInt</span><span class="p">(),</span>
        <span class="n">name</span><span class="p">:</span> <span class="nc">String</span> <span class="p">=</span> <span class="s">"The ${Random.nextInt()}th laptop"</span><span class="p">,</span>
        <span class="n">price</span><span class="p">:</span> <span class="nc">Double</span> <span class="p">=</span> <span class="nc">Random</span><span class="p">.</span><span class="nf">nextDouble</span><span class="p">(</span><span class="mf">1000.0</span><span class="p">,</span> <span class="mf">5000.0</span><span class="p">)</span>
    <span class="p">):</span> <span class="nc">Product</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nc">Product</span><span class="p">(</span><span class="n">id</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">price</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="k">fun</span> <span class="nf">order</span><span class="p">(</span>
        <span class="n">id</span><span class="p">:</span> <span class="nc">Int</span> <span class="p">=</span> <span class="nc">Random</span><span class="p">.</span><span class="nf">nextInt</span><span class="p">(),</span>
        <span class="n">customer</span><span class="p">:</span> <span class="nc">Customer</span> <span class="p">=</span> <span class="nf">customer</span><span class="p">(),</span>
        <span class="n">products</span><span class="p">:</span> <span class="nc">List</span><span class="p">&lt;</span><span class="nc">Product</span><span class="p">&gt;</span> <span class="p">=</span> <span class="nf">listOf</span><span class="p">(</span><span class="nf">product</span><span class="p">())</span>
    <span class="p">):</span> <span class="nc">Order</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nc">Order</span><span class="p">(</span><span class="n">id</span><span class="p">,</span> <span class="n">customer</span><span class="p">,</span> <span class="n">products</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="k">fun</span> <span class="nf">largeOrder</span><span class="p">(</span><span class="n">id</span><span class="p">:</span> <span class="nc">Int</span> <span class="p">=</span> <span class="nc">Random</span><span class="p">.</span><span class="nf">nextInt</span><span class="p">(),</span> <span class="n">customer</span><span class="p">:</span> <span class="nc">Customer</span> <span class="p">=</span> <span class="nf">customer</span><span class="p">()):</span> <span class="nc">Order</span> <span class="p">{</span>
        <span class="kd">val</span> <span class="py">products</span> <span class="p">=</span> <span class="nc">List</span><span class="p">(</span><span class="mi">100</span><span class="p">)</span> <span class="p">{</span> <span class="nf">product</span><span class="p">(</span><span class="n">id</span> <span class="p">=</span> <span class="n">it</span><span class="p">,</span> <span class="n">name</span> <span class="p">=</span> <span class="s">"Product$it"</span><span class="p">)</span> <span class="p">}</span>
        <span class="k">return</span> <span class="nc">Order</span><span class="p">(</span><span class="n">id</span><span class="p">,</span> <span class="n">customer</span><span class="p">,</span> <span class="n">products</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p><a href="https://github.com/akrystian/object-mother/blob/main/src/test/kotlin/pro/adamski/objectMother/ObjectMother.kt">Pełny kod na GitHub</a></p>

<h3 id="objectmother-w-javie">ObjectMother w Javie</h3>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">package</span> <span class="nn">pro.adamski.objectMother</span><span class="o">;</span>

<span class="kn">import</span> <span class="nn">java.util.ArrayList</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.List</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">java.util.Random</span><span class="o">;</span>

<span class="kd">public</span> <span class="kd">class</span> <span class="nc">ObjectMotherJava</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">Random</span> <span class="n">random</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Random</span><span class="o">();</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="nc">CustomerBuilder</span> <span class="nf">customer</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="k">new</span> <span class="nf">CustomerBuilder</span><span class="o">()</span>
                <span class="o">.</span><span class="na">withId</span><span class="o">(</span><span class="n">random</span><span class="o">.</span><span class="na">nextInt</span><span class="o">())</span>
                <span class="o">.</span><span class="na">withName</span><span class="o">(</span><span class="s">"John Doe"</span> <span class="o">+</span> <span class="n">random</span><span class="o">.</span><span class="na">nextInt</span><span class="o">())</span>
                <span class="o">.</span><span class="na">withEmail</span><span class="o">(</span><span class="s">"info-"</span> <span class="o">+</span> <span class="n">random</span><span class="o">.</span><span class="na">nextInt</span><span class="o">()</span> <span class="o">+</span> <span class="s">"@example.com"</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="nc">ProductBuilder</span> <span class="nf">product</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="k">new</span> <span class="nf">ProductBuilder</span><span class="o">()</span>
                <span class="o">.</span><span class="na">withId</span><span class="o">(</span><span class="n">random</span><span class="o">.</span><span class="na">nextInt</span><span class="o">())</span>
                <span class="o">.</span><span class="na">withName</span><span class="o">(</span><span class="s">"The "</span> <span class="o">+</span> <span class="n">random</span><span class="o">.</span><span class="na">nextInt</span><span class="o">()</span> <span class="o">+</span> <span class="s">"th laptop"</span><span class="o">)</span>
                <span class="o">.</span><span class="na">withPrice</span><span class="o">(</span><span class="n">random</span><span class="o">.</span><span class="na">nextDouble</span><span class="o">()</span> <span class="o">*</span> <span class="o">(</span><span class="mf">5000.0</span> <span class="o">-</span> <span class="mf">1000.0</span><span class="o">)</span> <span class="o">+</span> <span class="mf">1000.0</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="nc">OrderBuilder</span> <span class="nf">order</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="k">new</span> <span class="nf">OrderBuilder</span><span class="o">()</span>
                <span class="o">.</span><span class="na">withId</span><span class="o">(</span><span class="n">random</span><span class="o">.</span><span class="na">nextInt</span><span class="o">())</span>
                <span class="o">.</span><span class="na">withCustomer</span><span class="o">(</span><span class="n">customer</span><span class="o">().</span><span class="na">build</span><span class="o">())</span>
                <span class="o">.</span><span class="na">addProduct</span><span class="o">(</span><span class="n">product</span><span class="o">().</span><span class="na">build</span><span class="o">());</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="nc">Order</span> <span class="nf">largeOrder</span><span class="o">()</span> <span class="o">{</span>
        <span class="nc">OrderBuilder</span> <span class="n">orderBuilder</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">OrderBuilder</span><span class="o">()</span>
                <span class="o">.</span><span class="na">withId</span><span class="o">(</span><span class="n">random</span><span class="o">.</span><span class="na">nextInt</span><span class="o">())</span>
                <span class="o">.</span><span class="na">withCustomer</span><span class="o">(</span><span class="n">customer</span><span class="o">().</span><span class="na">build</span><span class="o">());</span>

        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">100</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
            <span class="n">orderBuilder</span><span class="o">.</span><span class="na">addProduct</span><span class="o">(</span><span class="n">product</span><span class="o">().</span><span class="na">withId</span><span class="o">(</span><span class="n">i</span><span class="o">).</span><span class="na">withName</span><span class="o">(</span><span class="s">"Product"</span> <span class="o">+</span> <span class="n">i</span><span class="o">).</span><span class="na">build</span><span class="o">());</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">orderBuilder</span><span class="o">.</span><span class="na">build</span><span class="o">();</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p><a href="https://github.com/akrystian/object-mother/blob/main/src/test/java/pro/adamski/objectMother/ObjectMotherJava.java">Pełny kod fluent builderami na GitHub</a></p>

<h3 id="testy-w-junit-5">Testy w JUnit 5</h3>

<div class="language-kotlin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="nn">pro.adamski.objectMother</span>

<span class="k">import</span> <span class="nn">org.assertj.core.api.Assertions.assertThat</span>
<span class="k">import</span> <span class="nn">org.junit.jupiter.api.Test</span>

<span class="kd">class</span> <span class="nc">OrderTest</span> <span class="p">{</span>

    <span class="nd">@Test</span>
    <span class="k">fun</span> <span class="nf">testCustomOrder</span><span class="p">()</span> <span class="p">{</span>
        <span class="c1">// Given</span>
        <span class="kd">val</span> <span class="py">customProduct</span> <span class="p">=</span> <span class="nc">ObjectMother</span><span class="p">.</span><span class="nf">product</span><span class="p">(</span><span class="n">name</span> <span class="p">=</span> <span class="s">"Custom Laptop"</span><span class="p">,</span> <span class="n">price</span> <span class="p">=</span> <span class="mf">2000.0</span><span class="p">)</span>

        <span class="c1">// When</span>
        <span class="kd">val</span> <span class="py">customOrder</span> <span class="p">=</span> <span class="nc">ObjectMother</span><span class="p">.</span><span class="nf">order</span><span class="p">(</span><span class="n">products</span> <span class="p">=</span> <span class="nf">listOf</span><span class="p">(</span><span class="n">customProduct</span><span class="p">))</span>

        <span class="c1">// Then</span>
        <span class="nf">assertOrderProduct</span><span class="p">(</span><span class="n">customOrder</span><span class="p">.</span><span class="n">products</span><span class="p">.</span><span class="nf">first</span><span class="p">(),</span> <span class="s">"Custom Laptop"</span><span class="p">,</span> <span class="mf">2000.0</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="nd">@Test</span>
    <span class="k">fun</span> <span class="nf">testRandomLargeOrder</span><span class="p">()</span> <span class="p">{</span>
        <span class="c1">// When</span>
        <span class="kd">val</span> <span class="py">largeOrder</span> <span class="p">=</span> <span class="nc">ObjectMother</span><span class="p">.</span><span class="nf">largeOrder</span><span class="p">()</span>

        <span class="c1">// Then</span>
        <span class="nf">assertOrderProducts</span><span class="p">(</span><span class="n">largeOrder</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mf">1000.0</span><span class="o">..</span><span class="mf">5000.0</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="nd">@Test</span>
    <span class="k">fun</span> <span class="nf">testCustomOrderJava</span><span class="p">()</span> <span class="p">{</span>
        <span class="c1">// Given</span>
        <span class="kd">val</span> <span class="py">customProduct</span> <span class="p">=</span> <span class="nc">ObjectMotherJava</span><span class="p">.</span><span class="nf">product</span><span class="p">().</span><span class="nf">withName</span><span class="p">(</span><span class="s">"Custom Laptop"</span><span class="p">).</span><span class="nf">withPrice</span><span class="p">(</span><span class="mf">2000.0</span><span class="p">).</span><span class="nf">build</span><span class="p">()</span>

        <span class="c1">// When</span>
        <span class="kd">val</span> <span class="py">customOrder</span> <span class="p">=</span> <span class="nc">ObjectMotherJava</span><span class="p">.</span><span class="nf">order</span><span class="p">().</span><span class="nf">withProducts</span><span class="p">(</span><span class="nf">listOf</span><span class="p">(</span><span class="n">customProduct</span><span class="p">)).</span><span class="nf">build</span><span class="p">()</span>

        <span class="c1">// Then</span>
        <span class="nf">assertOrderProduct</span><span class="p">(</span><span class="n">customOrder</span><span class="p">.</span><span class="n">products</span><span class="p">.</span><span class="nf">first</span><span class="p">(),</span> <span class="s">"Custom Laptop"</span><span class="p">,</span> <span class="mf">2000.0</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="nd">@Test</span>
    <span class="k">fun</span> <span class="nf">testRandomLargeOrderJava</span><span class="p">()</span> <span class="p">{</span>
        <span class="c1">// When</span>
        <span class="kd">val</span> <span class="py">largeOrder</span> <span class="p">=</span> <span class="nc">ObjectMotherJava</span><span class="p">.</span><span class="nf">largeOrder</span><span class="p">()</span>

        <span class="c1">// Then</span>
        <span class="nf">assertOrderProducts</span><span class="p">(</span><span class="n">largeOrder</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mf">1000.0</span><span class="o">..</span><span class="mf">5000.0</span><span class="p">)</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">fun</span> <span class="nf">assertOrderProducts</span><span class="p">(</span>
        <span class="n">largeOrder</span><span class="p">:</span> <span class="nc">Order</span><span class="p">,</span>
        <span class="n">numberOfProducts</span><span class="p">:</span> <span class="nc">Int</span><span class="p">,</span>
        <span class="n">priceRange</span><span class="p">:</span> <span class="nc">ClosedFloatingPointRange</span><span class="p">&lt;</span><span class="nc">Double</span><span class="p">&gt;</span>
    <span class="p">)</span> <span class="p">{</span>
        <span class="nf">assertThat</span><span class="p">(</span><span class="n">largeOrder</span><span class="p">.</span><span class="n">products</span><span class="p">).</span><span class="nf">hasSize</span><span class="p">(</span><span class="n">numberOfProducts</span><span class="p">)</span>
        <span class="nf">assertThat</span><span class="p">(</span><span class="n">largeOrder</span><span class="p">.</span><span class="n">products</span><span class="p">).</span><span class="nf">allMatch</span> <span class="p">{</span>
            <span class="n">it</span><span class="p">.</span><span class="n">price</span> <span class="k">in</span> <span class="n">priceRange</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">private</span> <span class="k">fun</span> <span class="nf">assertOrderProduct</span><span class="p">(</span><span class="n">firstProduct</span><span class="p">:</span> <span class="nc">Product</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nc">String</span><span class="p">,</span> <span class="n">price</span><span class="p">:</span> <span class="nc">Double</span><span class="p">)</span> <span class="p">{</span>
        <span class="nf">assertThat</span><span class="p">(</span><span class="n">firstProduct</span><span class="p">.</span><span class="n">name</span><span class="p">).</span><span class="nf">isEqualTo</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
        <span class="nf">assertThat</span><span class="p">(</span><span class="n">firstProduct</span><span class="p">.</span><span class="n">price</span><span class="p">).</span><span class="nf">isEqualTo</span><span class="p">(</span><span class="n">price</span><span class="p">)</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p><a href="https://github.com/akrystian/object-mother/blob/main/src/test/kotlin/pro/adamski/objectMother/OrderTest.kt">Pełny kod na GitHub</a></p>

<h2 id="podsumowanie">Podsumowanie</h2>

<p>Wzorzec ObjectMother jest bardzo użyteczny, zwłaszcza w dużych projektach z rozbudowaną bazą testów. Pomaga w utrzymaniu
czystego i efektywnego kodu testowego. W przypadku implementacji w Javie zastosowanie fluent builderów pozwala na
jeszcze większą czytelność kodu testowego.</p>

<h2 id="bibliografia">Bibliografia</h2>

<ol>
  <li><a href="https://martinfowler.com/bliki/ObjectMother.html">ObjectMother</a></li>
  <li><a href="https://reflectoring.io/objectmother-fluent-builder/">Combining Object Mother and Fluent Builder for the Ultimate Test Data Factory</a></li>
</ol>]]></content><author><name></name></author><summary type="html"><![CDATA[Wzorzec ObjectMother]]></summary></entry><entry><title type="html">Confitura 2023 - Testing the untestable</title><link href="https://adamski.pro/2023/06/27/confitura-testowanie.html" rel="alternate" type="text/html" title="Confitura 2023 - Testing the untestable" /><published>2023-06-27T00:00:00+00:00</published><updated>2023-06-27T00:00:00+00:00</updated><id>https://adamski.pro/2023/06/27/confitura-testowanie</id><content type="html" xml:base="https://adamski.pro/2023/06/27/confitura-testowanie.html"><![CDATA[<h1 id="confitura-2023---testing-the-untestable">Confitura 2023 - Testing the untestable</h1>

<p>W ostatnio miałem okazje uczestniczyć w konferencji <a href="https://2023.confitura.pl/">Confitura</a>. Jedna z prezentacji
okazała się szczególnie ciekawa.</p>

<h2 id="testing-the-untestable---patterns-and-use-cases-analysis">Testing the untestable - patterns and use cases analysis</h2>

<p>Opis prezentacji:</p>
<blockquote>
  <p>Autor prezentacji: Piotr Stawirej</p>

  <p>Zaprezentuję, jak można uprościć aplikację i umożliwić jej testowanie poprzez analizę napotkanych przypadków i
zastosowanych rozwiązań. Skupimy się na niestandardowych przypadkach oraz często powtarzalnych sytuacjach, które
występują podczas naszej pracy. Nauczymy się jak testować problematyczne klasy, integrację z bibliotekami,
frameworkami
i usługami zewnętrznymi, jak skutecznie używać zaślepek (fakes), co mockować, a czego nie, jak testować aplikacje
wielowątkowe, jak przyspieszać testy integracyjne, jak testować kod zależny od czasu i działania bez widocznego
efektu,
jak testować tolerancję na błędy oraz jak ponownie wykorzystać akceptacyjne testy jednostkowe jako testy integracyjne
lub API. Omówimy, dlaczego warto stosować Property Based Testing dla Value Object’ów, jak testować obiekty mutowalne,
zapis (persistence), czy testować logowanie, jak testować kod asynchroniczny. Poznamy przydatne heurystyki testowania
oraz alternatywę dla testów wydajnościowych.</p>
</blockquote>

<h1 id="wprowadzenie">Wprowadzenie</h1>

<p>Poniżej przedstawiam kilka moim zdaniem szczególnie istotnych aspektów przedstawionych w prezentacji.</p>

<h2 id="pojęcia">Pojęcia</h2>

<h3 id="fake">Fake</h3>

<p>Fake to implementacja prostego obiektu, która udaje funkcjonalność rzeczywistego obiektu, ale w sposób
uproszczony. Fake są często tworzone ręcznie jako proste implementacje interfejsów lub klas, które na potrzeby testów
mają zachowywać się podobnie do prawdziwych obiektów.</p>

<h3 id="mock">Mock</h3>

<p>Mock to obiekt, który symuluje zachowanie innych obiektów w systemie, umożliwiając kontrolowanie i sprawdzanie
interakcji. Mocki są często tworzone przy użyciu bibliotek (np. Mockito) i
pozwalają programistom na kontrolowanie, jak obiekty testowane współdziałają z innymi zależnościami.</p>

<h2 id="sposoby-na-testowanie-problematycznych-klas">Sposoby na testowanie problematycznych klas</h2>

<h3 id="1-optymalizacja-czasu-wykonania-testów">1. Optymalizacja czasu wykonania testów:</h3>

<p>Jednym z ciekawych problemów omawianych podczas niedawnej prezentacji był przypadek testowy, który restartował kontekst
Springa przed każdą metodą testową, co skutkowało znacznym wydłużeniem czasu wykonania testów. Aby temu zaradzić, warto
poszukać bardziej efektywnych sposobów przygotowania się do testów. W opisanym przykładzie zamiast restartu zastosowano
metodę setup, która usuwała wszystkie wiersze z bazy danych, skracając czas wykonania z 27 sekund do kilkuset
milisekund. Ta optymalizacja znacząco poprawiła cały proces testowania.</p>

<h3 id="2-wykorzystanie-implementacji-fake-zamiast-prostych-mocków">2. Wykorzystanie implementacji Fake zamiast prostych Mocków</h3>

<p>Innym interesującym podejściem podkreślonym w prezentacji było stosowanie implementacji Fake jako alternatywy dla
prostych Mocków. Implementacje Fake mają przewagę ponownego wykorzystania w wielu testach. Przykładem tego podejścia był
proste <a href="https://github.com/stawirej/financial-system/blob/d02f291f3b289bf392c7c3f6e05fccefdc634669/src/main/java/infrastructure/InMemoryRepository.java">repozytorium oparte na mapie</a>.</p>

<h3 id="3-testy-jednostkowe-jako-testy-na-wyższym-poziomie">3. Testy jednostkowe jako testy na wyższym poziomie</h3>

<p>Niezwykle interesującym przypadkiem omówionym podczas prezentacji było wykorzystanie testów jednostkowych jako testów na
wyższym poziomie. Proces ten polegał na wyodrębnieniu interfejsu z komponentu odpowiedzialnego za <a href="https://github.com/stawirej/financial-system/blob/d02f291f3b289bf392c7c3f6e05fccefdc634669/src/main/java/application/FinancialSystem.java">przypadki użycia</a> (np.
serwisu aplikacyjnego w kontekście Domain-Driven Design). Następnie napisano <a href="https://github.com/stawirej/financial-system/blob/d02f291f3b289bf392c7c3f6e05fccefdc634669/src/test/java/test/pyramid/strategy/application/FinancialSystemRise_scenarios.java">test jednostkowy</a>, który korzystał tylko z
Mocków lub implementacji Fake, aby sprawdzić funkcjonalność aplikacji. Ten sam test mógł zostać skonfigurowany tak, aby
korzystał z prawdziwych implementacji, na przykład repozytorium osadzonego lub opartego na kontenerach testowych. Co
więcej, ten sam test mógł być rozszerzony o testowanie interfejsu API poprzez zastąpienie komponentu implementującego
przypadki użycia <a href="https://github.com/stawirej/financial-system/blob/d02f291f3b289bf392c7c3f6e05fccefdc634669/src/test/java/ice/cream/cone/anti/pattern/strategy/automatization/FinancialSystemServiceAgent.java">klientem API</a> lub rozwiązaniem opartym na <a href="https://github.com/stawirej/financial-system/blob/d02f291f3b289bf392c7c3f6e05fccefdc634669/src/test/java/test/pyramid/strategy/presentation/frontend/automatization/FinancialSystemFrontendAgent.java">Selenium</a>.</p>

<h3 id="4-zapewnienie-obserwowalnych-wyników-testów">4. Zapewnienie obserwowalnych wyników testów</h3>

<p>Czasami w testach można napotkać wyniki, które są trudne do obserwacji, co może prowadzić do niejasności lub błędnego
przypuszczenia, że oczekiwane zachowanie nie zostało zaimplementowane. Jest to szczególnie trudne w przypadku podejścia
Test-Driven Development (TDD). Aby temu zaradzić, warto jawnie uwzględnić oczekiwane zachowanie w teście, nawet jeśli
nie jest ono bezpośrednio obserwowalne.</p>

<h1 id="linki-do-kodu-źródłowego-i-prezentacji">Linki do kodu źródłowego i prezentacji</h1>

<ul>
  <li>https://github.com/stawirej/financial-system</li>
  <li>https://amazingcode.pl/talks/testing-the-untestable.pdf</li>
</ul>

<h1 id="podsumowanie">Podsumowanie</h1>

<p>Testowanie oprogramowania może być wyzwaniem, ale zastosowanie odpowiednich strategii może znacznie poprawić efektywność
i jakość procesu testowania. Optymalizacja czasu wykonania testów, wykorzystanie implementacji Fake, testowanie na
różnych poziomach abstrakcji i zapewnienie obserwowalności wyników to tylko kilka z wielu przydatnych strategii. Mając
świadomość tych wyzwań i stosując odpowiednie metody, programiści mogą skutecznie radzić sobie z trudnościami związanymi
z testowaniem i dostarczać lepsze oprogramowanie.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Confitura 2023 - Testing the untestable]]></summary></entry><entry><title type="html">Serwer Spring Boot w jednym pliku.</title><link href="https://adamski.pro/groovy/spring/boot/2020/04/03/simple-spring-bootapp-groovy.html" rel="alternate" type="text/html" title="Serwer Spring Boot w jednym pliku." /><published>2020-04-03T00:00:00+00:00</published><updated>2020-04-03T00:00:00+00:00</updated><id>https://adamski.pro/groovy/spring/boot/2020/04/03/simple-spring-bootapp-groovy</id><content type="html" xml:base="https://adamski.pro/groovy/spring/boot/2020/04/03/simple-spring-bootapp-groovy.html"><![CDATA[<h1 id="serwer-spring-boot-w-jednym-pliku">Serwer Spring Boot w jednym pliku.</h1>

<p>W pełni funkcjonalny serwer możemy utworzyć za pomocą tylko jednego pliku <code class="language-plaintext highlighter-rouge">server.groovy</code>.</p>

<h2 id="wymagania">Wymagania:</h2>
<ul>
  <li>Java SDK 8</li>
  <li>Groovy SDK</li>
</ul>

<h2 id="przepis">Przepis</h2>

<p>Dodać plik <code class="language-plaintext highlighter-rouge">server.groovy</code></p>
<div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Grapes</span><span class="o">([</span>
        <span class="nd">@GrabConfig</span><span class="o">(</span><span class="n">systemClassLoader</span> <span class="o">=</span> <span class="kc">true</span><span class="o">),</span>
        <span class="nd">@Grab</span><span class="o">(</span><span class="n">group</span> <span class="o">=</span> <span class="s1">'org.springframework.boot'</span><span class="o">,</span> <span class="n">module</span> <span class="o">=</span> <span class="s1">'spring-boot-starter-web'</span><span class="o">,</span> <span class="n">version</span> <span class="o">=</span> <span class="s1">'2.2.6.RELEASE'</span><span class="o">),</span>
        <span class="nd">@GrabExclude</span><span class="o">(</span><span class="n">group</span> <span class="o">=</span> <span class="s1">'org.springframework.boot'</span><span class="o">,</span> <span class="n">module</span> <span class="o">=</span> <span class="s1">'spring-boot-starter-tomcat'</span><span class="o">),</span>
        <span class="nd">@Grab</span><span class="o">(</span><span class="n">group</span> <span class="o">=</span> <span class="s1">'org.springframework.boot'</span><span class="o">,</span> <span class="n">module</span> <span class="o">=</span> <span class="s1">'spring-boot-starter-undertow'</span><span class="o">,</span> <span class="n">version</span> <span class="o">=</span> <span class="s1">'2.2.6.RELEASE'</span><span class="o">)</span>
<span class="o">])</span>

<span class="kn">import</span> <span class="nn">org.springframework.boot.autoconfigure.SpringBootApplication</span>
<span class="kn">import</span> <span class="nn">org.springframework.web.bind.annotation.*</span>
<span class="kn">import</span> <span class="nn">org.springframework.boot.SpringApplication</span>

<span class="cm">/**
 * @author akrystian
 */</span>
<span class="nd">@SpringBootApplication</span>
<span class="nd">@RestController</span>
<span class="kd">class</span> <span class="nc">App</span> <span class="o">{</span>

    <span class="nd">@RequestMapping</span><span class="o">(</span><span class="s2">"/"</span><span class="o">)</span>
    <span class="n">String</span> <span class="nf">simpleEndpoint</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="s2">"Hello!!"</span>
    <span class="o">}</span>
<span class="o">}</span>

<span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="n">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
    <span class="n">SpringApplication</span><span class="o">.</span><span class="na">run</span><span class="o">(</span><span class="n">App</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">args</span><span class="o">)</span>
<span class="o">}</span>
</code></pre></div></div>

<h2 id="uruchomienie">Uruchomienie</h2>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>groovy server.groovy
</code></pre></div></div>

<h2 id="logi-z-uruchomienia">Logi z uruchomienia</h2>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.6.RELEASE)

2020-04-04 02:28:52.463  INFO 32601 --- [           main] groovy.ui.GroovyMain                     : Starting GroovyMain v2.5.5 on Legion with PID 32601 (/home/krystian/.sdkman/candidates/groovy/current/lib/groovy-2.5.5.jar started by krystian in /home/krystian/IdeaProjects/code.conference.site)
2020-04-04 02:28:52.469  INFO 32601 --- [           main] groovy.ui.GroovyMain                     : No active profile set, falling back to default profiles: default
2020-04-04 02:28:53.391  WARN 32601 --- [           main] io.undertow.websockets.jsr               : UT026010: Buffer pool was not set on WebSocketDeploymentInfo, the default pool will be used
2020-04-04 02:28:53.411  INFO 32601 --- [           main] io.undertow.servlet                      : Initializing Spring embedded WebApplicationContext
2020-04-04 02:28:53.411  INFO 32601 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 871 ms
2020-04-04 02:28:53.586  INFO 32601 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-04-04 02:28:53.716  WARN 32601 --- [           main] .b.a.g.t.GroovyTemplateAutoConfiguration : Cannot find template location: classpath:/templates/ (please add some templates, check your Groovy configuration, or set spring.groovy.template.check-template-location=false)
2020-04-04 02:28:53.859  INFO 32601 --- [           main] io.undertow                              : starting server: Undertow - 2.0.30.Final
2020-04-04 02:28:53.866  INFO 32601 --- [           main] org.xnio                                 : XNIO version 3.3.8.Final
2020-04-04 02:28:53.873  INFO 32601 --- [           main] org.xnio.nio                             : XNIO NIO Implementation Version 3.3.8.Final
2020-04-04 02:28:53.994  INFO 32601 --- [           main] o.s.b.w.e.u.UndertowServletWebServer     : Undertow started on port(s) 8080 (http) with context path ''
2020-04-04 02:28:53.998  INFO 32601 --- [           main] groovy.ui.GroovyMain                     : Started GroovyMain in 1.996 seconds (JVM running for 4.051)
2020-04-04 02:29:32.110  INFO 32601 --- [  XNIO-1 task-1] io.undertow.servlet                      : Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-04-04 02:29:32.110  INFO 32601 --- [  XNIO-1 task-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2020-04-04 02:29:32.118  INFO 32601 --- [  XNIO-1 task-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 8 ms
</code></pre></div></div>

<h2 id="test-działania">Test działania</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> curl <span class="nt">-i</span> http://localhost:8080/
  HTTP/1.1 200 OK
  Connection: keep-alive
  Content-Type: text/plain<span class="p">;</span><span class="nv">charset</span><span class="o">=</span>UTF-8
  Content-Length: 7
  Date: Sat, 04 Apr 2020 00:42:57 GMT

  Hello!!%
</code></pre></div></div>]]></content><author><name></name></author><category term="groovy" /><category term="spring" /><category term="boot" /><summary type="html"><![CDATA[Serwer Spring Boot w jednym pliku.]]></summary></entry><entry><title type="html">Coderetreat - dlaczego warto tam być.</title><link href="https://adamski.pro/tdd/2019/11/19/coderetreat.html" rel="alternate" type="text/html" title="Coderetreat - dlaczego warto tam być." /><published>2019-11-19T00:00:00+00:00</published><updated>2019-11-19T00:00:00+00:00</updated><id>https://adamski.pro/tdd/2019/11/19/coderetreat</id><content type="html" xml:base="https://adamski.pro/tdd/2019/11/19/coderetreat.html"><![CDATA[<h1 id="coderetreat---dlaczego-warto-tam-być">Coderetreat - dlaczego warto tam być.</h1>

<p>W tym wpisie postaram się zdefiniować dlaczego warto uczestniczyć w coderetreat.</p>

<h2 id="moja-historia">Moja historia</h2>

<p>Ja byłem już na dwóch takich warsztatach (cztery i pięć lat temu). Z każdego wyniosłem wiele, ale jedną zapamiętałem najbardziej. Był to czas kiedy zaczynałem moją karierę programisty, pisząc w NetBeans. Zasiadłem w parze z programistą zdecydowanie bardziej zaawansowanym ode mnie. To była 4 iteracja, więc problem już był raczej rozpracowany (implementacja oparta o zbiór aktywnych komórek, a nie żadna tablica dwuwymiarowa z booleanami). Z tych czterdziestu pięciu minut wyniosłem:</p>
<ul>
  <li>Tworzenie kodu na zasadach refactoringu</li>
  <li>Dobre opanowanie IDE - IntellJ</li>
  <li>Tworzenie kodu w metodyce DDD</li>
</ul>

<h2 id="organizacja-warsztatu">Organizacja warsztatu</h2>

<p>Warsztat składa się z 5 iteracji. Każda kolejna iteracja wprowadza inne ograniczenia, które można wybrać <a href="https://www.coderetreat.org/pages/facilitating/activity-catalog/">(lista przykładowych)</a>. Podczas warsztatu zalecane jest przestrzeganie <a href="https://pl.wikipedia.org/wiki/Test-driven_development">Test Driven Development</a> i <a href="https://martinfowler.com/bliki/BeckDesignRules.html">4 zasad tworzenia oprogramowania</a>.</p>

<h3 id="iteracja">Iteracja</h3>

<ul>
  <li>Prezentacja ograniczeń iteracji - W tym kroku prowadzący prezentują jakie są ograniczenia danej iteracji (np. nie można używać myszki lub nie można używać pętli)</li>
  <li>Implementacja problemu - 45 minut - Osoby siedzące w parach starają się zaimplementować algorytm gry w życie respektując ograniczenia nałożone przez prowadzących.</li>
  <li>Usunięcie kodu - Trzeba usunąć kod który się stworzyło w obecnej iteracji.</li>
  <li>Retrospekcja - Tutaj wszyscy uczestnicy dzielą się spostrzeżeniami na temat obecnej iteracji.</li>
  <li>Zmiana pary - W kolejnej iteracji dobrze być w parze z osobą z którą jeszcze nie miało się okazji być w parze wcześniej.</li>
</ul>

<h2 id="co-decyduje-o-wyjątkowości-tej-formuły">Co decyduje o wyjątkowości tej formuły</h2>

<h3 id="trening-tdd">Trening TDD</h3>

<p>Praktyczne zapoznanie z podejściem Test Driven Development. Programowanie z podziałem na fazy:</p>
<ul>
  <li>Red - implementacja testu który nie przechodzi</li>
  <li>Green - najprostsza implementacja która powoduje przejście testu</li>
  <li>Refactor - refaktoryzacja kodu</li>
</ul>

<h3 id="programowanie-w-parach">Programowanie w parach</h3>

<p>Podczas pracy w parach ważna jest współpraca z drugą osobą. Na początku trzeba ustalić wspólną koncepcję. Zdecydować o kolejności w jakiej będziemy implementować rozwiązanie problemu. Dodatkowo warto sobie wypracować model współpracy, bo ostatecznie kod trafia na jedną klawiaturę.</p>

<h3 id="zobaczenie-warsztatu-kilku-innych-programistów">Zobaczenie warsztatu kilku innych programistów</h3>

<p>Można zobaczyć warsztat innej osoby, a także podzielić się swoim. Najczęściej na pierwszy ogień idą skróty klawiaturowe oraz ciekawe funkcjonalności IDE. Ale na drugim miejscu jest sposób tworzenia kodu oraz sposób rozwiązywania problemów.</p>

<h3 id="wymiana-wiedzy-na-retrospekcjach">Wymiana wiedzy na retrospekcjach</h3>

<p>Wymiana spostrzeżeń w retrospekcjach jest bezcenna. Najczęściej zadawane są trzy pytania:</p>
<ul>
  <li>Co udało się Wam zrobić?</li>
  <li>Czego nowego nauczyłeś się w ostatniej iteracji?</li>
  <li>Co Cię zaskoczyło w ostatniej iteracji?</li>
</ul>

<p>Często większość osób zaczyna z różnymi implementacjami opartymi o dwuwymiarową tablicę. W kolejnych iteracjach rozwiązanie problemu kierowane jest w stronę bardziej optymalnego rozwiązania (dodatkowym aspektem tego jest mieszanie się osób w kolejnych iteracjach podczas programowania w parach).</p>

<h3 id="ograniczenia-mające-na-celu-zmianę-spojrzenia-na-ten-sam-problem">Ograniczenia mające na celu zmianę spojrzenia na ten sam problem.</h3>

<p>Rozwiązywanie kilka razy tego samego problemu mogłoby się okazać niezbyt ciekawe. Na szczęście kolejne iteracje dodają inne ograniczenia w rozwiązaniu tego samego problemu. Weźmy trzy przykładowe:</p>
<ul>
  <li>Bez myszki - Powoduje to większe skupienie na skrótach klawiaturowych, funkcjach wbudowanych w IDE oraz skrótach systemowych.</li>
  <li>Nazwy klas są czasownikami, a nazwy metod są rzeczownikami - To jest pogwałcenie ogólnie stosowanych reguł nazewnictwa w programowaniu obiektowym. Co pokazuje wagę tego aspektu w programowaniu.</li>
  <li>Cichy ping-pong - Czyli jest podział na programistę i testera ale nie można ze sobą rozmawiać. Dlatego ciężko jest ustalić wspólne podejście do rozwiązywania problemu. Ważne jest aby kod wyrażał intencje programisty.</li>
</ul>

<h2 id="podsumowanie">Podsumowanie</h2>

<p>Moim zdaniem ciężko znaleźć bardziej wszechstronny warsztat, który zapewniałby wymianę wiedzy w tak krótkim czasie. Iteracyjny charakter i wymiana par ma na celu skomasować doświadczenia płynące od wielu osób z którymi można programować w parze. Dodatkowo retrospekcje całej grupy przynoszą często wiele nieoczekiwanych wniosków do których trudno dojść w pojedynczej parze.</p>]]></content><author><name></name></author><category term="TDD" /><summary type="html"><![CDATA[Coderetreat - dlaczego warto tam być.]]></summary></entry><entry><title type="html">Nowinki ze świata IT</title><link href="https://adamski.pro/2019/03/05/programmers-news.html" rel="alternate" type="text/html" title="Nowinki ze świata IT" /><published>2019-03-05T00:00:00+00:00</published><updated>2019-03-05T00:00:00+00:00</updated><id>https://adamski.pro/2019/03/05/programmers-news</id><content type="html" xml:base="https://adamski.pro/2019/03/05/programmers-news.html"><![CDATA[<h1 id="nowości-ze-świata-it">Nowości ze świata IT</h1>

<p>Kilka przydatnych stron gdzie można 
znaleźć najnowsze nowości ze świata 
IT.</p>

<h2 id="hacker-news">Hacker news</h2>
<ul>
  <li><a href="https://news.ycombinator.com">hacker news</a></li>
  <li><a href="http://www.hntoplinks.com/week">hacker news agregator</a></li>
</ul>

<h2 id="reddit">Reddit</h2>
<ul>
  <li><a href="https://www.reddit.com/r/programming/top/?t=week">reddit.com</a></li>
</ul>]]></content><author><name></name></author><summary type="html"><![CDATA[Nowości ze świata IT]]></summary></entry><entry><title type="html">Dodanie niezaufanego certyfikatu https do keystore</title><link href="https://adamski.pro/java/2018/11/08/add-cert-to-keytool.html" rel="alternate" type="text/html" title="Dodanie niezaufanego certyfikatu https do keystore" /><published>2018-11-08T00:00:00+00:00</published><updated>2018-11-08T00:00:00+00:00</updated><id>https://adamski.pro/java/2018/11/08/add-cert-to-keytool</id><content type="html" xml:base="https://adamski.pro/java/2018/11/08/add-cert-to-keytool.html"><![CDATA[<h1 id="dodanie-niezaufanego-certyfikatu-https-do-keystore">Dodanie niezaufanego certyfikatu https do keystore</h1>

<h2 id="opis-problemu">Opis problemu</h2>

<p>Umożliwienie zestawienia połączenia https do niezaufanej usługi za pomocą aplikacji uruchomionej na maszynie wirtualnej java.</p>

<p>Często na etapie tworzenia usług mamy potrzebę do połączenia do usługi która jest udostępniona po protokole https, ale certyfikat takiej strony nie jest zaufany. Gdy uruchomimy taką w aplikacje na maszynie wirtualnej java która łączy się do niezaufanego adresu https to dostaniemy błąd.</p>

<h2 id="przykład">Przykład</h2>

<p>Przykładowy skrypt w groovym.</p>

<div class="language-groovy highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">def</span> <span class="n">content</span> <span class="o">=</span> <span class="k">new</span> <span class="n">URL</span><span class="o">(</span><span class="s2">"https://self-signed.badssl.com/"</span><span class="o">).</span><span class="na">text</span>
<span class="n">println</span> <span class="n">content</span>
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ groovy scratch_1.groovy                                                     
Caught: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at scratch_1.run(scratch_1.groovy:1)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        ... 1 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        ... 1 more
</code></pre></div></div>

<h2 id="wymagania">Wymagania</h2>
<ul>
  <li>jre</li>
  <li>openssl</li>
</ul>

<h2 id="rozwiązanie">Rozwiązanie</h2>

<p>Aby maszyna wirtualna pozwoliła się połączyć do niezaufanej usługi https wymagane jest:</p>
<ul>
  <li>Pobranie certyfikatu niezaufanej usługi</li>
  <li>(Opcjonalny) stworzenie keystore</li>
  <li>Dodanie pobranego certyfikatu do keystore</li>
</ul>

<p>Przydatny może się okazać poniższy skrypt (addToJavaKeystore.sh):</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>

<span class="nb">set</span> <span class="nt">-e</span>
<span class="nb">set</span> <span class="nt">-u</span>

command_exists <span class="o">()</span>
<span class="o">{</span>
    <span class="nb">type</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> <span class="o">&gt;</span>/dev/null 2&gt;&amp;1 <span class="o">||</span> <span class="o">{</span> <span class="nb">echo</span> <span class="s2">"I require </span><span class="k">${</span><span class="nv">1</span><span class="k">}</span><span class="s2"> but it's not installed.  Aborting."</span> <span class="o">&gt;</span>&amp;2<span class="p">;</span> <span class="nb">exit </span>1<span class="p">;</span> <span class="o">}</span>
<span class="o">}</span>

command_exists openssl
command_exists <span class="nb">sed

</span><span class="nv">HOST</span><span class="o">=</span><span class="k">${</span><span class="nv">1</span><span class="k">}</span>
<span class="nv">PORT</span><span class="o">=</span>443
<span class="nv">JAVA_HOME</span><span class="o">=</span><span class="k">${</span><span class="nv">2</span><span class="k">}</span>
<span class="nv">KEYSTORE_FILE</span><span class="o">=</span><span class="k">${</span><span class="nv">JAVA_HOME</span><span class="k">}</span>/jre/lib/security/cacerts
<span class="nv">KEYSTORE_PASS</span><span class="o">=</span>changeit
<span class="nv">KEYTOOL_FILE</span><span class="o">=</span><span class="k">${</span><span class="nv">JAVA_HOME</span><span class="k">}</span>/bin/keytool
<span class="nv">CERT_FILE</span><span class="o">=</span><span class="k">${</span><span class="nv">HOST</span><span class="k">}</span>.cert

<span class="c"># save the SSL certificate to file</span>
openssl s_client <span class="nt">-connect</span> <span class="k">${</span><span class="nv">HOST</span><span class="k">}</span>:<span class="k">${</span><span class="nv">PORT</span><span class="k">}</span> &lt;/dev/null <span class="se">\</span>
| <span class="nb">sed</span> <span class="nt">-ne</span> <span class="s1">'/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'</span> <span class="o">&gt;</span> <span class="k">${</span><span class="nv">CERT_FILE</span><span class="k">}</span>

<span class="c"># create a keystore and import certificate</span>
<span class="k">${</span><span class="nv">KEYTOOL_FILE</span><span class="k">}</span> <span class="nt">-import</span> <span class="nt">-noprompt</span> <span class="nt">-trustcacerts</span> <span class="se">\</span>
<span class="nt">-alias</span> <span class="k">${</span><span class="nv">HOST</span><span class="k">}</span> <span class="nt">-file</span> <span class="k">${</span><span class="nv">CERT_FILE</span><span class="k">}</span> <span class="se">\</span>
<span class="nt">-keystore</span> <span class="k">${</span><span class="nv">KEYSTORE_FILE</span><span class="k">}</span> <span class="nt">-storepass</span> <span class="k">${</span><span class="nv">KEYSTORE_PASS</span><span class="k">}</span>

<span class="c"># verify we have got it.</span>
<span class="k">${</span><span class="nv">KEYTOOL_FILE</span><span class="k">}</span> <span class="nt">-list</span> <span class="nt">-v</span> <span class="nt">-keystore</span> <span class="k">${</span><span class="nv">KEYSTORE_FILE</span><span class="k">}</span> <span class="nt">-storepass</span> <span class="k">${</span><span class="nv">KEYSTORE_PASS</span><span class="k">}</span> <span class="nt">-alias</span> <span class="k">${</span><span class="nv">HOST</span><span class="k">}</span>

<span class="c"># remove cert file</span>
<span class="nb">rm</span> <span class="nt">-f</span> <span class="k">${</span><span class="nv">CERT_FILE</span><span class="k">}</span>
</code></pre></div></div>

<h2 id="użycie">Użycie</h2>

<p>Po uruchomieniu skryptu dla domeny <code class="language-plaintext highlighter-rouge">self-signed.badssl.com</code></p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo</span> ./addToJavaKeystore.sh self-signed.badssl.com <span class="nv">$JAVA_HOME</span>
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ sudo ./addToJavaKeystore.sh self-signed.badssl.com $JAVA_HOME
depth=0 C = US, ST = California, L = San Francisco, O = BadSSL, CN = *.badssl.com
verify error:num=18:self signed certificate
verify return:1
depth=0 C = US, ST = California, L = San Francisco, O = BadSSL, CN = *.badssl.com
verify error:num=10:certificate has expired
notAfter=Aug  8 21:17:05 2018 GMT
verify return:1
depth=0 C = US, ST = California, L = San Francisco, O = BadSSL, CN = *.badssl.com
notAfter=Aug  8 21:17:05 2018 GMT
verify return:1
DONE
Certificate was added to keystore
Alias name: self-signed.badssl.com
Creation date: 2019-10-09
Entry type: trustedCertEntry

Owner: CN=*.badssl.com, O=BadSSL, L=San Francisco, ST=California, C=US
Issuer: CN=*.badssl.com, O=BadSSL, L=San Francisco, ST=California, C=US
Serial number: 86fb4dc8e5dd0f18
Valid from: Mon Aug 08 23:17:05 CEST 2016 until: Wed Aug 08 23:17:05 CEST 2018
Certificate fingerprints:
         MD5:  46:10:F4:1F:93:A3:EE:58:E0:CC:69:BE:1C:71:E0:C0
         SHA1: 64:14:50:D9:4A:65:FA:EB:3B:63:10:28:D8:E8:6C:95:43:1D:B8:11
         SHA256: 28:C9:E8:BA:A6:03:EE:94:00:2E:CA:CD:37:C1:50:91:DC:A6:E1:AC:8E:D4:29:E3:11:89:7C:6C:72:20:34:B0
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3

Extensions: 

#1: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
  CA:false
  PathLen: undefined
]

#2: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
  DNSName: *.badssl.com
  DNSName: badssl.com
]
</code></pre></div></div>

<p>Wykonanie skyptu po dodaniu domeny do <code class="language-plaintext highlighter-rouge">keystore</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ groovy scratch_1.groovy                                      
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;meta charset="utf-8"&gt;
  &lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt;
  &lt;link rel="shortcut icon" href="/icons/favicon-red.ico"/&gt;
  &lt;link rel="apple-touch-icon" href="/icons/icon-red.png"/&gt;
  &lt;title&gt;self-signed.badssl.com&lt;/title&gt;
  &lt;link rel="stylesheet" href="/style.css"&gt;
  &lt;style&gt;body { background: red; }&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div id="content"&gt;
  &lt;h1 style="font-size: 12vw;"&gt;
    self-signed.&lt;br&gt;badssl.com
  &lt;/h1&gt;
&lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;

</code></pre></div></div>

<p>Udało się połączyć do niezaufanej usługi https. :)</p>]]></content><author><name></name></author><category term="java" /><summary type="html"><![CDATA[Dodanie niezaufanego certyfikatu https do keystore]]></summary></entry><entry><title type="html">Usługa REST-owa w 5 min</title><link href="https://adamski.pro/java/spring/boot/2018/05/31/simple-spring-bootapp.html" rel="alternate" type="text/html" title="Usługa REST-owa w 5 min" /><published>2018-05-31T00:00:00+00:00</published><updated>2018-05-31T00:00:00+00:00</updated><id>https://adamski.pro/java/spring/boot/2018/05/31/simple-spring-bootapp</id><content type="html" xml:base="https://adamski.pro/java/spring/boot/2018/05/31/simple-spring-bootapp.html"><![CDATA[<h1 id="usługa-rest-owa-w-5-min">Usługa REST-owa w 5 min</h1>

<p>Czy można stworzyć usługę w 5 min? Można.</p>

<h2 id="wymagania">Wymagania:</h2>
<ul>
  <li>Java SDK 8</li>
  <li>Gradle</li>
</ul>

<h2 id="przepis">Przepis:</h2>

<ul>
  <li>Aby utworzyć pusty projekt w gradle dla aplikacji w Javie.</li>
</ul>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gradle init <span class="nt">--type</span> java-application
</code></pre></div></div>

<ul>
  <li>Dodać zależności i pluginy w <code class="language-plaintext highlighter-rouge">build.gradle</code></li>
</ul>

<div class="language-gradle highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">plugins</span> <span class="o">{</span>
    <span class="n">id</span> <span class="s1">'java'</span>
    <span class="n">id</span> <span class="s2">"org.springframework.boot"</span> <span class="n">version</span> <span class="s2">"2.0.2.RELEASE"</span>
<span class="o">}</span>

<span class="k">dependencies</span> <span class="o">{</span>
    <span class="n">compile</span> <span class="s1">'org.springframework.boot:spring-boot-starter-web:2.0.2.RELEASE'</span>

    <span class="n">testCompile</span> <span class="s1">'junit:junit:4.12'</span>
<span class="o">}</span>

<span class="k">repositories</span> <span class="o">{</span>
    <span class="n">jcenter</span><span class="o">()</span>
<span class="o">}</span>
</code></pre></div></div>

<ul>
  <li>
    <p>Usunąć wszystkie pliki *.java z katalogu src i test.</p>
  </li>
  <li>
    <p>Dodać klasę aplikacji</p>
  </li>
</ul>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">package</span> <span class="nn">pro.adamski</span><span class="o">;</span>

<span class="kn">import</span> <span class="nn">org.springframework.boot.SpringApplication</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.springframework.boot.autoconfigure.SpringBootApplication</span><span class="o">;</span>

<span class="cm">/**
 * @author akrystian
 */</span>
<span class="nd">@SpringBootApplication</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">App</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
        <span class="nc">SpringApplication</span><span class="o">.</span><span class="na">run</span><span class="o">(</span><span class="nc">App</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">args</span><span class="o">);</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<ul>
  <li>Dodać klasę kontrolera</li>
</ul>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">package</span> <span class="nn">pro.adamski.endpoints</span><span class="o">;</span>

<span class="kn">import</span> <span class="nn">org.springframework.web.bind.annotation.RequestMapping</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.springframework.web.bind.annotation.RestController</span><span class="o">;</span>

<span class="cm">/**
 * @author akrystian
 */</span>
<span class="nd">@RestController</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">SimpleEndpoint</span> <span class="o">{</span>

    <span class="nd">@RequestMapping</span><span class="o">(</span><span class="s">"/"</span><span class="o">)</span>
    <span class="kd">public</span> <span class="nc">String</span> <span class="nf">simpleEndpoint</span><span class="o">(){</span>
        <span class="k">return</span> <span class="s">"Hello!!"</span><span class="o">;</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<ul>
  <li>Zbudować aplikację</li>
</ul>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./gradlew bootJar
</code></pre></div></div>

<ul>
  <li>Uruchomić aplikację</li>
</ul>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>java <span class="nt">-jar</span> ./build/libs/microBootApp.jar
</code></pre></div></div>

<ul>
  <li>Możemy przetestować działanie aplikacji</li>
</ul>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-i</span> http://localhost:8080/
HTTP/1.1 200
Content-Type: text/plain<span class="p">;</span><span class="nv">charset</span><span class="o">=</span>UTF-8
Content-Length: 7
Date: Thu, 31 May 2018 19:33:41 GMT

Hello!!%
</code></pre></div></div>]]></content><author><name></name></author><category term="java" /><category term="spring" /><category term="boot" /><summary type="html"><![CDATA[Usługa REST-owa w 5 min]]></summary></entry><entry><title type="html">Windows - automatyzacja procesu instalacji oprogramowania</title><link href="https://adamski.pro/windows/2017/02/08/windows-automate.html" rel="alternate" type="text/html" title="Windows - automatyzacja procesu instalacji oprogramowania" /><published>2017-02-08T15:35:05+00:00</published><updated>2017-02-08T15:35:05+00:00</updated><id>https://adamski.pro/windows/2017/02/08/windows-automate</id><content type="html" xml:base="https://adamski.pro/windows/2017/02/08/windows-automate.html"><![CDATA[<h1 id="windows--automatyzacja-procesu-instalacji-oprogramowania">Windows- automatyzacja procesu instalacji oprogramowania</h1>

<p>Instalacja oprogramowania na Windowsie zajmuje dużo czasu i jest często zagmatwana. Z pomocą mogą przyjść narzędzia automatyzujące ten proces.</p>

<ul>
  <li><a href="https://ninite.com/">Ninite</a> – Pobrany ze strony instalator który zainstaluje wybrane przez nas oprogramowanie.</li>
  <li><a href="https://chocolatey.org/">Chocolatey</a> – Menadżer pakietów podobny do <code class="language-plaintext highlighter-rouge">apt-get</code> znanego z Ubuntu.</li>
</ul>]]></content><author><name></name></author><category term="windows" /><summary type="html"><![CDATA[Windows- automatyzacja procesu instalacji oprogramowania]]></summary></entry><entry><title type="html">Bazy danych</title><link href="https://adamski.pro/db/2016/09/08/cassandra-modeling.html" rel="alternate" type="text/html" title="Bazy danych" /><published>2016-09-08T15:35:05+00:00</published><updated>2016-09-08T15:35:05+00:00</updated><id>https://adamski.pro/db/2016/09/08/cassandra-modeling</id><content type="html" xml:base="https://adamski.pro/db/2016/09/08/cassandra-modeling.html"><![CDATA[<h1 id="bazy-danych">Bazy danych</h1>

<h2 id="cassandra">Cassandra</h2>

<ul>
  <li>Oficjalna dokumentacja
    <ul>
      <li><a href="http://www.datastax.com/resources/data-modeling">http://www.datastax.com/resources/data-modeling</a></li>
      <li><a href="http://www.datastax.com/dev/blog/basic-rules-of-cassandra-data-modeling">http://www.datastax.com/dev/blog/basic-rules-of-cassandra-data-modeling</a></li>
    </ul>
  </li>
  <li>Inne zasoby
    <ul>
      <li><a href="http://www.ebaytechblog.com/2012/07/16/cassandra-data-modeling-best-practices-part-1/">http://www.ebaytechblog.com/2012/07/16/cassandra-data-modeling-best-practices-part-1/</a></li>
      <li><a href="http://www.ebaytechblog.com/2012/08/14/cassandra-data-modeling-best-practices-part-2/">http://www.ebaytechblog.com/2012/08/14/cassandra-data-modeling-best-practices-part-2/</a></li>
    </ul>
  </li>
</ul>

<h2 id="mongo">Mongo</h2>

<ul>
  <li>Oficjalny kurs
Kurs wideo z <a href="https://university.mongodb.com/courses/catalog">mongo university</a></li>
</ul>]]></content><author><name></name></author><category term="db" /><summary type="html"><![CDATA[Bazy danych]]></summary></entry></feed>