Dica Java: Métodos estáticos não! #003

Essa dica: é muito importante para quem faz testes unitários!

Imagine uma service com 2 métodos que possuem a mesma validação (IF) como abaixo:

<span>@Service</span>
<span>@RequiredArgsConstructor</span>
<span>public</span> <span>class</span> <span>PersonService</span> <span>{</span>
<span>private</span> <span>static</span> <span>final</span> <span>int</span> <span>ADULT_AGE</span> <span>=</span> <span>18</span><span>;</span>
<span>public</span> <span>void</span> <span>createAdult</span><span>(</span><span>final</span> <span>PersonDomain</span> <span>person</span><span>)</span> <span>{</span>
<span>if</span> <span>(</span><span>ADULT_AGE</span> <span>></span> <span>Period</span><span>.</span><span>between</span><span>(</span><span>person</span><span>.</span><span>birthdate</span><span>(),</span> <span>LocalDate</span><span>.</span><span>now</span><span>()).</span><span>getYears</span><span>())</span> <span>{</span>
<span>throw</span> <span>new</span> <span>UnsupportedOperationException</span><span>(</span><span>"person.is.not.adult"</span><span>);</span>
<span>}</span>
<span>}</span>
<span>public</span> <span>void</span> <span>registerCNH</span><span>(</span><span>final</span> <span>PersonDomain</span> <span>person</span><span>)</span> <span>{</span>
<span>if</span> <span>(</span><span>ADULT_AGE</span> <span>></span> <span>Period</span><span>.</span><span>between</span><span>(</span><span>person</span><span>.</span><span>birthdate</span><span>(),</span> <span>LocalDate</span><span>.</span><span>now</span><span>()).</span><span>getYears</span><span>())</span> <span>{</span>
<span>throw</span> <span>new</span> <span>UnsupportedOperationException</span><span>(</span><span>"person.is.not.adult"</span><span>);</span>
<span>}</span>
<span>}</span>
<span>}</span>
<span>@Service</span>
<span>@RequiredArgsConstructor</span>
<span>public</span> <span>class</span> <span>PersonService</span> <span>{</span>

    <span>private</span> <span>static</span> <span>final</span> <span>int</span> <span>ADULT_AGE</span> <span>=</span> <span>18</span><span>;</span>

    <span>public</span> <span>void</span> <span>createAdult</span><span>(</span><span>final</span> <span>PersonDomain</span> <span>person</span><span>)</span> <span>{</span>
        <span>if</span> <span>(</span><span>ADULT_AGE</span> <span>></span> <span>Period</span><span>.</span><span>between</span><span>(</span><span>person</span><span>.</span><span>birthdate</span><span>(),</span> <span>LocalDate</span><span>.</span><span>now</span><span>()).</span><span>getYears</span><span>())</span> <span>{</span>
            <span>throw</span> <span>new</span> <span>UnsupportedOperationException</span><span>(</span><span>"person.is.not.adult"</span><span>);</span>
        <span>}</span>
    <span>}</span>

    <span>public</span> <span>void</span> <span>registerCNH</span><span>(</span><span>final</span> <span>PersonDomain</span> <span>person</span><span>)</span> <span>{</span>
        <span>if</span> <span>(</span><span>ADULT_AGE</span> <span>></span> <span>Period</span><span>.</span><span>between</span><span>(</span><span>person</span><span>.</span><span>birthdate</span><span>(),</span> <span>LocalDate</span><span>.</span><span>now</span><span>()).</span><span>getYears</span><span>())</span> <span>{</span>
            <span>throw</span> <span>new</span> <span>UnsupportedOperationException</span><span>(</span><span>"person.is.not.adult"</span><span>);</span>
        <span>}</span>
    <span>}</span>
<span>}</span>
@Service @RequiredArgsConstructor public class PersonService { private static final int ADULT_AGE = 18; public void createAdult(final PersonDomain person) { if (ADULT_AGE > Period.between(person.birthdate(), LocalDate.now()).getYears()) { throw new UnsupportedOperationException("person.is.not.adult"); } } public void registerCNH(final PersonDomain person) { if (ADULT_AGE > Period.between(person.birthdate(), LocalDate.now()).getYears()) { throw new UnsupportedOperationException("person.is.not.adult"); } } }

Enter fullscreen mode Exit fullscreen mode

Há uma replicação de código: IF + exceção.

Se o projeto tivesse testes unitários, para ter a cobertura teria que ser algo como o código abaixo:

<span>@ExtendWith</span><span>(</span><span>MockitoExtension</span><span>.</span><span>class</span><span>)</span>
<span>class</span> <span>PersonServiceTest</span> <span>{</span>
<span>@InjectMocks</span>
<span>private</span> <span>PersonService</span> <span>service</span><span>;</span>
<span>@Nested</span>
<span>class</span> <span>WhenCreateAdult</span> <span>{</span>
<span>@Test</span>
<span>void</span> <span>shouldDoesNotThrow</span><span>()</span> <span>{</span>
<span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>().</span><span>minusYears</span><span>(</span><span>18</span><span>));</span>
<span>assertDoesNotThrow</span><span>(()</span> <span>-></span> <span>service</span><span>.</span><span>createAdult</span><span>(</span><span>person</span><span>));</span>
<span>}</span>
<span>@Test</span>
<span>void</span> <span>shouldDoesNotThrow2</span><span>()</span> <span>{</span>
<span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>().</span><span>minusYears</span><span>(</span><span>19</span><span>));</span>
<span>assertDoesNotThrow</span><span>(()</span> <span>-></span> <span>service</span><span>.</span><span>createAdult</span><span>(</span><span>person</span><span>));</span>
<span>}</span>
<span>@Test</span>
<span>void</span> <span>shouldThrow</span><span>()</span> <span>{</span>
<span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>().</span><span>minusYears</span><span>(</span><span>17</span><span>));</span>
<span>assertThatThrownBy</span><span>(()</span> <span>-></span> <span>service</span><span>.</span><span>createAdult</span><span>(</span><span>person</span><span>))</span>
<span>.</span><span>isInstanceOf</span><span>(</span><span>UnsupportedOperationException</span><span>.</span><span>class</span><span>)</span>
<span>.</span><span>hasMessage</span><span>(</span><span>"person.is.not.adult"</span><span>);</span>
<span>}</span>
<span>}</span>
<span>@Nested</span>
<span>class</span> <span>WhenRegisterCNH</span> <span>{</span>
<span>@Test</span>
<span>void</span> <span>shouldDoesNotThrow</span><span>()</span> <span>{</span>
<span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>().</span><span>minusYears</span><span>(</span><span>18</span><span>));</span>
<span>assertDoesNotThrow</span><span>(()</span> <span>-></span> <span>service</span><span>.</span><span>registerCNH</span><span>(</span><span>person</span><span>));</span>
<span>}</span>
<span>@Test</span>
<span>void</span> <span>shouldDoesNotThrow2</span><span>()</span> <span>{</span>
<span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>().</span><span>minusYears</span><span>(</span><span>19</span><span>));</span>
<span>assertDoesNotThrow</span><span>(()</span> <span>-></span> <span>service</span><span>.</span><span>registerCNH</span><span>(</span><span>person</span><span>));</span>
<span>}</span>
<span>@Test</span>
<span>void</span> <span>shouldThrow</span><span>()</span> <span>{</span>
<span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>().</span><span>minusYears</span><span>(</span><span>17</span><span>));</span>
<span>assertThatThrownBy</span><span>(()</span> <span>-></span> <span>service</span><span>.</span><span>registerCNH</span><span>(</span><span>person</span><span>))</span>
<span>.</span><span>isInstanceOf</span><span>(</span><span>UnsupportedOperationException</span><span>.</span><span>class</span><span>)</span>
<span>.</span><span>hasMessage</span><span>(</span><span>"person.is.not.adult"</span><span>);</span>
<span>}</span>
<span>}</span>
<span>}</span>
<span>@ExtendWith</span><span>(</span><span>MockitoExtension</span><span>.</span><span>class</span><span>)</span>
<span>class</span> <span>PersonServiceTest</span> <span>{</span>

    <span>@InjectMocks</span>
    <span>private</span> <span>PersonService</span> <span>service</span><span>;</span>

    <span>@Nested</span>
    <span>class</span> <span>WhenCreateAdult</span> <span>{</span>

        <span>@Test</span>
        <span>void</span> <span>shouldDoesNotThrow</span><span>()</span> <span>{</span>
            <span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>().</span><span>minusYears</span><span>(</span><span>18</span><span>));</span>

            <span>assertDoesNotThrow</span><span>(()</span> <span>-></span> <span>service</span><span>.</span><span>createAdult</span><span>(</span><span>person</span><span>));</span>
        <span>}</span>

        <span>@Test</span>
        <span>void</span> <span>shouldDoesNotThrow2</span><span>()</span> <span>{</span>
            <span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>().</span><span>minusYears</span><span>(</span><span>19</span><span>));</span>

            <span>assertDoesNotThrow</span><span>(()</span> <span>-></span> <span>service</span><span>.</span><span>createAdult</span><span>(</span><span>person</span><span>));</span>
        <span>}</span>

        <span>@Test</span>
        <span>void</span> <span>shouldThrow</span><span>()</span> <span>{</span>
            <span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>().</span><span>minusYears</span><span>(</span><span>17</span><span>));</span>

            <span>assertThatThrownBy</span><span>(()</span> <span>-></span> <span>service</span><span>.</span><span>createAdult</span><span>(</span><span>person</span><span>))</span>
                <span>.</span><span>isInstanceOf</span><span>(</span><span>UnsupportedOperationException</span><span>.</span><span>class</span><span>)</span>
                <span>.</span><span>hasMessage</span><span>(</span><span>"person.is.not.adult"</span><span>);</span>
        <span>}</span>
    <span>}</span>

    <span>@Nested</span>
    <span>class</span> <span>WhenRegisterCNH</span> <span>{</span>

        <span>@Test</span>
        <span>void</span> <span>shouldDoesNotThrow</span><span>()</span> <span>{</span>
            <span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>().</span><span>minusYears</span><span>(</span><span>18</span><span>));</span>

            <span>assertDoesNotThrow</span><span>(()</span> <span>-></span> <span>service</span><span>.</span><span>registerCNH</span><span>(</span><span>person</span><span>));</span>
        <span>}</span>

        <span>@Test</span>
        <span>void</span> <span>shouldDoesNotThrow2</span><span>()</span> <span>{</span>
            <span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>().</span><span>minusYears</span><span>(</span><span>19</span><span>));</span>

            <span>assertDoesNotThrow</span><span>(()</span> <span>-></span> <span>service</span><span>.</span><span>registerCNH</span><span>(</span><span>person</span><span>));</span>
        <span>}</span>

        <span>@Test</span>
        <span>void</span> <span>shouldThrow</span><span>()</span> <span>{</span>
            <span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>().</span><span>minusYears</span><span>(</span><span>17</span><span>));</span>

            <span>assertThatThrownBy</span><span>(()</span> <span>-></span> <span>service</span><span>.</span><span>registerCNH</span><span>(</span><span>person</span><span>))</span>
                <span>.</span><span>isInstanceOf</span><span>(</span><span>UnsupportedOperationException</span><span>.</span><span>class</span><span>)</span>
                <span>.</span><span>hasMessage</span><span>(</span><span>"person.is.not.adult"</span><span>);</span>
        <span>}</span>
    <span>}</span>
<span>}</span>
@ExtendWith(MockitoExtension.class) class PersonServiceTest { @InjectMocks private PersonService service; @Nested class WhenCreateAdult { @Test void shouldDoesNotThrow() { final var person = new PersonDomain(LocalDate.now().minusYears(18)); assertDoesNotThrow(() -> service.createAdult(person)); } @Test void shouldDoesNotThrow2() { final var person = new PersonDomain(LocalDate.now().minusYears(19)); assertDoesNotThrow(() -> service.createAdult(person)); } @Test void shouldThrow() { final var person = new PersonDomain(LocalDate.now().minusYears(17)); assertThatThrownBy(() -> service.createAdult(person)) .isInstanceOf(UnsupportedOperationException.class) .hasMessage("person.is.not.adult"); } } @Nested class WhenRegisterCNH { @Test void shouldDoesNotThrow() { final var person = new PersonDomain(LocalDate.now().minusYears(18)); assertDoesNotThrow(() -> service.registerCNH(person)); } @Test void shouldDoesNotThrow2() { final var person = new PersonDomain(LocalDate.now().minusYears(19)); assertDoesNotThrow(() -> service.registerCNH(person)); } @Test void shouldThrow() { final var person = new PersonDomain(LocalDate.now().minusYears(17)); assertThatThrownBy(() -> service.registerCNH(person)) .isInstanceOf(UnsupportedOperationException.class) .hasMessage("person.is.not.adult"); } } }

Enter fullscreen mode Exit fullscreen mode

Terá então replicação de código e de teste unitário.

É comum para evitar a replicação de código, separar em outra classe e reaproveitar o mesmo código.

<span>public</span> <span>class</span> <span>PersonValidator</span> <span>{</span>
<span>private</span> <span>static</span> <span>final</span> <span>int</span> <span>ADULT_AGE</span> <span>=</span> <span>18</span><span>;</span>
<span>public</span> <span>static</span> <span>void</span> <span>verifyAdult</span><span>(</span><span>final</span> <span>PersonDomain</span> <span>person</span><span>)</span> <span>{</span>
<span>if</span> <span>(</span><span>ADULT_AGE</span> <span>></span> <span>Period</span><span>.</span><span>between</span><span>(</span><span>person</span><span>.</span><span>birthdate</span><span>(),</span> <span>LocalDate</span><span>.</span><span>now</span><span>()).</span><span>getYears</span><span>())</span> <span>{</span>
<span>throw</span> <span>new</span> <span>UnsupportedOperationException</span><span>(</span><span>"person.is.not.adult"</span><span>);</span>
<span>}</span>
<span>}</span>
<span>}</span>
<span>public</span> <span>class</span> <span>PersonValidator</span> <span>{</span>

    <span>private</span> <span>static</span> <span>final</span> <span>int</span> <span>ADULT_AGE</span> <span>=</span> <span>18</span><span>;</span>

    <span>public</span> <span>static</span> <span>void</span> <span>verifyAdult</span><span>(</span><span>final</span> <span>PersonDomain</span> <span>person</span><span>)</span> <span>{</span>
        <span>if</span> <span>(</span><span>ADULT_AGE</span> <span>></span> <span>Period</span><span>.</span><span>between</span><span>(</span><span>person</span><span>.</span><span>birthdate</span><span>(),</span> <span>LocalDate</span><span>.</span><span>now</span><span>()).</span><span>getYears</span><span>())</span> <span>{</span>
            <span>throw</span> <span>new</span> <span>UnsupportedOperationException</span><span>(</span><span>"person.is.not.adult"</span><span>);</span>
        <span>}</span>
    <span>}</span>
<span>}</span>
public class PersonValidator { private static final int ADULT_AGE = 18; public static void verifyAdult(final PersonDomain person) { if (ADULT_AGE > Period.between(person.birthdate(), LocalDate.now()).getYears()) { throw new UnsupportedOperationException("person.is.not.adult"); } } }

Enter fullscreen mode Exit fullscreen mode

Na service o código ficaria.

<span>@Service</span>
<span>@RequiredArgsConstructor</span>
<span>public</span> <span>class</span> <span>PersonService</span> <span>{</span>
<span>public</span> <span>void</span> <span>createAdult</span><span>(</span><span>final</span> <span>PersonDomain</span> <span>person</span><span>)</span> <span>{</span>
<span>PersonValidator</span><span>.</span><span>verifyAdult</span><span>(</span><span>person</span><span>);</span>
<span>}</span>
<span>public</span> <span>void</span> <span>registerCNH</span><span>(</span><span>final</span> <span>PersonDomain</span> <span>person</span><span>)</span> <span>{</span>
<span>PersonValidator</span><span>.</span><span>verifyAdult</span><span>(</span><span>person</span><span>);</span>
<span>}</span>
<span>}</span>
<span>@Service</span>
<span>@RequiredArgsConstructor</span>
<span>public</span> <span>class</span> <span>PersonService</span> <span>{</span>

    <span>public</span> <span>void</span> <span>createAdult</span><span>(</span><span>final</span> <span>PersonDomain</span> <span>person</span><span>)</span> <span>{</span>
        <span>PersonValidator</span><span>.</span><span>verifyAdult</span><span>(</span><span>person</span><span>);</span>
    <span>}</span>

    <span>public</span> <span>void</span> <span>registerCNH</span><span>(</span><span>final</span> <span>PersonDomain</span> <span>person</span><span>)</span> <span>{</span>
        <span>PersonValidator</span><span>.</span><span>verifyAdult</span><span>(</span><span>person</span><span>);</span>
    <span>}</span>
<span>}</span>
@Service @RequiredArgsConstructor public class PersonService { public void createAdult(final PersonDomain person) { PersonValidator.verifyAdult(person); } public void registerCNH(final PersonDomain person) { PersonValidator.verifyAdult(person); } }

Enter fullscreen mode Exit fullscreen mode

OK, foi resolvido a replicação do IF e do throw, porém o teste unitário ainda está replicado! E por isso é recomendado sempre usar Bean’s! Evitar o uso de métodos estáticos e transformar a classe em uma Bean.

<span>@Component</span>
<span>public</span> <span>class</span> <span>PersonValidator</span> <span>{</span>
<span>private</span> <span>static</span> <span>final</span> <span>int</span> <span>ADULT_AGE</span> <span>=</span> <span>18</span><span>;</span>
<span>public</span> <span>void</span> <span>verifyAdult</span><span>(</span><span>final</span> <span>PersonDomain</span> <span>person</span><span>)</span> <span>{</span>
<span>if</span> <span>(</span><span>ADULT_AGE</span> <span>></span> <span>Period</span><span>.</span><span>between</span><span>(</span><span>person</span><span>.</span><span>birthdate</span><span>(),</span> <span>LocalDate</span><span>.</span><span>now</span><span>()).</span><span>getYears</span><span>())</span> <span>{</span>
<span>throw</span> <span>new</span> <span>UnsupportedOperationException</span><span>(</span><span>"person.is.not.adult"</span><span>);</span>
<span>}</span>
<span>}</span>
<span>}</span>
<span>@Component</span>
<span>public</span> <span>class</span> <span>PersonValidator</span> <span>{</span>

    <span>private</span> <span>static</span> <span>final</span> <span>int</span> <span>ADULT_AGE</span> <span>=</span> <span>18</span><span>;</span>

    <span>public</span> <span>void</span> <span>verifyAdult</span><span>(</span><span>final</span> <span>PersonDomain</span> <span>person</span><span>)</span> <span>{</span>
        <span>if</span> <span>(</span><span>ADULT_AGE</span> <span>></span> <span>Period</span><span>.</span><span>between</span><span>(</span><span>person</span><span>.</span><span>birthdate</span><span>(),</span> <span>LocalDate</span><span>.</span><span>now</span><span>()).</span><span>getYears</span><span>())</span> <span>{</span>
            <span>throw</span> <span>new</span> <span>UnsupportedOperationException</span><span>(</span><span>"person.is.not.adult"</span><span>);</span>
        <span>}</span>
    <span>}</span>
<span>}</span>
@Component public class PersonValidator { private static final int ADULT_AGE = 18; public void verifyAdult(final PersonDomain person) { if (ADULT_AGE > Period.between(person.birthdate(), LocalDate.now()).getYears()) { throw new UnsupportedOperationException("person.is.not.adult"); } } }

Enter fullscreen mode Exit fullscreen mode

A PersonService com a injeção de dependência da nova Bean.

<span>@Service</span>
<span>@RequiredArgsConstructor</span>
<span>public</span> <span>class</span> <span>PersonService</span> <span>{</span>
<span>private</span> <span>final</span> <span>PersonValidator</span> <span>validator</span><span>;</span>
<span>public</span> <span>void</span> <span>createAdult</span><span>(</span><span>final</span> <span>PersonDomain</span> <span>person</span><span>)</span> <span>{</span>
<span>validator</span><span>.</span><span>verifyAdult</span><span>(</span><span>person</span><span>);</span>
<span>}</span>
<span>public</span> <span>void</span> <span>registerCNH</span><span>(</span><span>final</span> <span>PersonDomain</span> <span>person</span><span>)</span> <span>{</span>
<span>validator</span><span>.</span><span>verifyAdult</span><span>(</span><span>person</span><span>);</span>
<span>}</span>
<span>}</span>
<span>@Service</span>
<span>@RequiredArgsConstructor</span>
<span>public</span> <span>class</span> <span>PersonService</span> <span>{</span>

    <span>private</span> <span>final</span> <span>PersonValidator</span> <span>validator</span><span>;</span>

    <span>public</span> <span>void</span> <span>createAdult</span><span>(</span><span>final</span> <span>PersonDomain</span> <span>person</span><span>)</span> <span>{</span>
        <span>validator</span><span>.</span><span>verifyAdult</span><span>(</span><span>person</span><span>);</span>
    <span>}</span>

    <span>public</span> <span>void</span> <span>registerCNH</span><span>(</span><span>final</span> <span>PersonDomain</span> <span>person</span><span>)</span> <span>{</span>
        <span>validator</span><span>.</span><span>verifyAdult</span><span>(</span><span>person</span><span>);</span>
    <span>}</span>
<span>}</span>
@Service @RequiredArgsConstructor public class PersonService { private final PersonValidator validator; public void createAdult(final PersonDomain person) { validator.verifyAdult(person); } public void registerCNH(final PersonDomain person) { validator.verifyAdult(person); } }

Enter fullscreen mode Exit fullscreen mode

O teste unitário fica único.

<span>@ExtendWith</span><span>(</span><span>MockitoExtension</span><span>.</span><span>class</span><span>)</span>
<span>class</span> <span>PersonValidatorTest</span> <span>{</span>
<span>@InjectMocks</span>
<span>private</span> <span>PersonValidator</span> <span>validator</span><span>;</span>
<span>@Nested</span>
<span>class</span> <span>WhenVerifyAdult</span> <span>{</span>
<span>@Test</span>
<span>void</span> <span>shouldDoesNotThrow</span><span>()</span> <span>{</span>
<span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>().</span><span>minusYears</span><span>(</span><span>18</span><span>));</span>
<span>assertDoesNotThrow</span><span>(()</span> <span>-></span> <span>validator</span><span>.</span><span>verifyAdult</span><span>(</span><span>person</span><span>));</span>
<span>}</span>
<span>@Test</span>
<span>void</span> <span>shouldDoesNotThrow2</span><span>()</span> <span>{</span>
<span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>().</span><span>minusYears</span><span>(</span><span>19</span><span>));</span>
<span>assertDoesNotThrow</span><span>(()</span> <span>-></span> <span>validator</span><span>.</span><span>verifyAdult</span><span>(</span><span>person</span><span>));</span>
<span>}</span>
<span>@Test</span>
<span>void</span> <span>shouldThrow</span><span>()</span> <span>{</span>
<span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>().</span><span>minusYears</span><span>(</span><span>17</span><span>));</span>
<span>assertThatThrownBy</span><span>(()</span> <span>-></span> <span>validator</span><span>.</span><span>verifyAdult</span><span>(</span><span>person</span><span>))</span>
<span>.</span><span>isInstanceOf</span><span>(</span><span>UnsupportedOperationException</span><span>.</span><span>class</span><span>)</span>
<span>.</span><span>hasMessage</span><span>(</span><span>"person.is.not.adult"</span><span>);</span>
<span>}</span>
<span>}</span>
<span>}</span>
<span>@ExtendWith</span><span>(</span><span>MockitoExtension</span><span>.</span><span>class</span><span>)</span>
<span>class</span> <span>PersonValidatorTest</span> <span>{</span>

    <span>@InjectMocks</span>
    <span>private</span> <span>PersonValidator</span> <span>validator</span><span>;</span>

    <span>@Nested</span>
    <span>class</span> <span>WhenVerifyAdult</span> <span>{</span>

        <span>@Test</span>
        <span>void</span> <span>shouldDoesNotThrow</span><span>()</span> <span>{</span>
            <span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>().</span><span>minusYears</span><span>(</span><span>18</span><span>));</span>

            <span>assertDoesNotThrow</span><span>(()</span> <span>-></span> <span>validator</span><span>.</span><span>verifyAdult</span><span>(</span><span>person</span><span>));</span>
        <span>}</span>

        <span>@Test</span>
        <span>void</span> <span>shouldDoesNotThrow2</span><span>()</span> <span>{</span>
            <span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>().</span><span>minusYears</span><span>(</span><span>19</span><span>));</span>

            <span>assertDoesNotThrow</span><span>(()</span> <span>-></span> <span>validator</span><span>.</span><span>verifyAdult</span><span>(</span><span>person</span><span>));</span>
        <span>}</span>

        <span>@Test</span>
        <span>void</span> <span>shouldThrow</span><span>()</span> <span>{</span>
            <span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>().</span><span>minusYears</span><span>(</span><span>17</span><span>));</span>

            <span>assertThatThrownBy</span><span>(()</span> <span>-></span> <span>validator</span><span>.</span><span>verifyAdult</span><span>(</span><span>person</span><span>))</span>
                <span>.</span><span>isInstanceOf</span><span>(</span><span>UnsupportedOperationException</span><span>.</span><span>class</span><span>)</span>
                <span>.</span><span>hasMessage</span><span>(</span><span>"person.is.not.adult"</span><span>);</span>
        <span>}</span>
    <span>}</span>
<span>}</span>
@ExtendWith(MockitoExtension.class) class PersonValidatorTest { @InjectMocks private PersonValidator validator; @Nested class WhenVerifyAdult { @Test void shouldDoesNotThrow() { final var person = new PersonDomain(LocalDate.now().minusYears(18)); assertDoesNotThrow(() -> validator.verifyAdult(person)); } @Test void shouldDoesNotThrow2() { final var person = new PersonDomain(LocalDate.now().minusYears(19)); assertDoesNotThrow(() -> validator.verifyAdult(person)); } @Test void shouldThrow() { final var person = new PersonDomain(LocalDate.now().minusYears(17)); assertThatThrownBy(() -> validator.verifyAdult(person)) .isInstanceOf(UnsupportedOperationException.class) .hasMessage("person.is.not.adult"); } } }

Enter fullscreen mode Exit fullscreen mode

E o teste unitário na PersonService torna-se apenas um verify.

<span>@ExtendWith</span><span>(</span><span>MockitoExtension</span><span>.</span><span>class</span><span>)</span>
<span>class</span> <span>PersonServiceTest</span> <span>{</span>
<span>@InjectMocks</span>
<span>private</span> <span>PersonService</span> <span>service</span><span>;</span>
<span>@Mock</span>
<span>private</span> <span>PersonValidator</span> <span>validator</span><span>;</span>
<span>@Nested</span>
<span>class</span> <span>WhenCreateAdult</span> <span>{</span>
<span>@Test</span>
<span>void</span> <span>shouldDoesNotThrow</span><span>()</span> <span>{</span>
<span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>());</span>
<span>assertDoesNotThrow</span><span>(()</span> <span>-></span> <span>service</span><span>.</span><span>createAdult</span><span>(</span><span>person</span><span>));</span>
<span>verify</span><span>(</span><span>validator</span><span>).</span><span>verifyAdult</span><span>(</span><span>person</span><span>);</span>
<span>}</span>
<span>}</span>
<span>@Nested</span>
<span>class</span> <span>WhenRegisterCNH</span> <span>{</span>
<span>@Test</span>
<span>void</span> <span>shouldDoesNotThrow</span><span>()</span> <span>{</span>
<span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>());</span>
<span>assertDoesNotThrow</span><span>(()</span> <span>-></span> <span>service</span><span>.</span><span>registerCNH</span><span>(</span><span>person</span><span>));</span>
<span>verify</span><span>(</span><span>validator</span><span>).</span><span>verifyAdult</span><span>(</span><span>person</span><span>);</span>
<span>}</span>
<span>}</span>
<span>}</span>
<span>@ExtendWith</span><span>(</span><span>MockitoExtension</span><span>.</span><span>class</span><span>)</span>
<span>class</span> <span>PersonServiceTest</span> <span>{</span>

    <span>@InjectMocks</span>
    <span>private</span> <span>PersonService</span> <span>service</span><span>;</span>

    <span>@Mock</span>
    <span>private</span> <span>PersonValidator</span> <span>validator</span><span>;</span>

    <span>@Nested</span>
    <span>class</span> <span>WhenCreateAdult</span> <span>{</span>

        <span>@Test</span>
        <span>void</span> <span>shouldDoesNotThrow</span><span>()</span> <span>{</span>
            <span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>());</span>

            <span>assertDoesNotThrow</span><span>(()</span> <span>-></span> <span>service</span><span>.</span><span>createAdult</span><span>(</span><span>person</span><span>));</span>

            <span>verify</span><span>(</span><span>validator</span><span>).</span><span>verifyAdult</span><span>(</span><span>person</span><span>);</span>
        <span>}</span>
    <span>}</span>

    <span>@Nested</span>
    <span>class</span> <span>WhenRegisterCNH</span> <span>{</span>

        <span>@Test</span>
        <span>void</span> <span>shouldDoesNotThrow</span><span>()</span> <span>{</span>
            <span>final</span> <span>var</span> <span>person</span> <span>=</span> <span>new</span> <span>PersonDomain</span><span>(</span><span>LocalDate</span><span>.</span><span>now</span><span>());</span>

            <span>assertDoesNotThrow</span><span>(()</span> <span>-></span> <span>service</span><span>.</span><span>registerCNH</span><span>(</span><span>person</span><span>));</span>

            <span>verify</span><span>(</span><span>validator</span><span>).</span><span>verifyAdult</span><span>(</span><span>person</span><span>);</span>
        <span>}</span>
    <span>}</span>
<span>}</span>
@ExtendWith(MockitoExtension.class) class PersonServiceTest { @InjectMocks private PersonService service; @Mock private PersonValidator validator; @Nested class WhenCreateAdult { @Test void shouldDoesNotThrow() { final var person = new PersonDomain(LocalDate.now()); assertDoesNotThrow(() -> service.createAdult(person)); verify(validator).verifyAdult(person); } } @Nested class WhenRegisterCNH { @Test void shouldDoesNotThrow() { final var person = new PersonDomain(LocalDate.now()); assertDoesNotThrow(() -> service.registerCNH(person)); verify(validator).verifyAdult(person); } } }

Enter fullscreen mode Exit fullscreen mode

Obtém-se o mesmo resultado com o mesmo objetivo e ainda mantém boas práticas de código e testes.

No exemplo foi utilizado apenas um método com retorno void e utilizado apenas em dois locais do sistema, porém esse exemplo se aplica a cenários mais complexos onde condicionais ou estados de objetos influenciam e alteram os comportamentos dos componentes do sistema em N locais. Essa dica torna mais fácil, mais eficiente e menos desgastantes os testes unitários.

原文链接:Dica Java: Métodos estáticos não! #003

© 版权声明
THE END
喜欢就支持一下吧
点赞11 分享
Never say die.
永不言弃
评论 抢沙发

请登录后发表评论

    暂无评论内容