AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Test

skill-snk-devcenter-addon-studio-test · by snk-devcenter

Escreve, revisa e amplia testes JUnit 5 + Mockito 4.11 para Sankhya Addon Studio — mock de `JapeRepository` via `@Mock`, mock estático de `JapeSession`/`SessionFile` (mockito-inline), fixtures, controllers, services, repositories, mappers. Use ao criar, alterar, revisar ou ampliar cobertura de testes em `src/test/java/`, ao diagnosticar testes flaky/falhando, ou ao tocar em código com `@Test`/`@M…

No reviews yet
0 installs
6 views
0.0% view→install

Install

$ agentstack add skill-snk-devcenter-addon-studio-test

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-snk-devcenter-addon-studio-test)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
13d ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Test? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Testes Backend - Addon Studio 2.0 (JUnit + Mockito)

Documento define como desenvolver testes automatizados backend Addon Studio 2.0 com libs de mercado.

Objetivo

  • Garantir comportamento regras negocio.
  • Permitir refator seguro.
  • Reduzir regressao em servicos e mapeamentos.

Bibliotecas recomendadas

  • JUnit 5 (org.junit.jupiter)
  • Mockito 4.x (org.mockito) — usar 4.11.0. Projeto Java 8. Mockito 5.x exige Java 11+.
  • AssertJ (assercoes fluentes)
  • mockito-inline (mock estatico JapeSession, SessionFile etc.)

O que testar

Foque em logica de negocio isolada — classes de servico, regras em entidades, mapeamentos. Pular o que e framework / SDK.

Regra pratica:

  • Testar unidade de negocio isolada.
  • Nao testar framework Addon Studio em si.
  • Nao acoplar teste unitario a banco real, Wildfly ou infra externa.
  • Onde organizar arquivos de teste fica a criterio da arquitetura do projeto (convencao Maven/Gradle: espelhar pacote do src/main/java em src/test/java).

Padrao nome:

  • Classe teste: Test
  • Metodo teste: deve_quando()

Configuracao completa (Gradle)

1. build.gradle raiz — adicionar classpath do plugin de log visual

buildscript {
    repositories {
        // ... repositorios existentes ...
        maven {
            url = uri("https://plugins.gradle.org/m2/")
        }
    }

    dependencies {
        // ... dependencias existentes ...
        classpath "com.adarshr:gradle-test-logger-plugin:3.2.0"
    }
}

2. /build.gradle — dependencias e configuracao

apply plugin: 'com.adarshr.test-logger'

testlogger {
    theme 'mocha'
    showExceptions true
    showStackTraces true
    showFullStackTraces false
    showCauses true
    slowThreshold 2000
    showSummary true
    showPassed true
    showSkipped true
    showFailed true
    showStandardStreams false
    showPassedStandardStreams false
    showFailedStandardStreams true
    logLevel 'lifecycle'
}

dependencies {
    // SDK do Addon Studio no classpath de teste.
    // Obrigatorio: repositorios (ex.: TdcXyzCadastroRepository) estendem JapeRepository
    // do SDK da Sankhya, que so e disponibilizado para compilacao principal pelo
    // plugin Gradle do Studio. Sem isso, o compilador nao resolve findByPK/save nos testes.
    testImplementation 'br.com.sankhya.studio:sdk-sankhya:2+'

    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2'
    testRuntimeOnly    'org.junit.jupiter:junit-jupiter-engine:5.10.2'

    // mockito-core 4.x: compativel com Java 8 (5.x exige Java 11+)
    testImplementation 'org.mockito:mockito-core:4.11.0'
    testImplementation 'org.mockito:mockito-junit-jupiter:4.11.0'

    // mockito-inline: necessario para mockar metodos estaticos (JapeSession, SessionFile etc.)
    testImplementation 'org.mockito:mockito-inline:4.11.0'

    testImplementation 'org.assertj:assertj-core:3.26.3'
}

test {
    useJUnitPlatform()
}

Output visual test-logger tema mocha similar a Jest:

com.example.addon.ProcessarEntidadeServiceTest

  ✔ deveProcessar_quandoGatewayRetornarDados()
  ✔ deveLancarEntityNotFoundException_quandoEntidadeNaoEncontrada()
  ✘ deveLancarRuntimeException_quandoRepositorioFalhar()
    ...stack trace...

82 passing (2.9s)
1 failing

Template de teste unitario

import java.util.Arrays;
import java.util.List;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.mockito.Mockito.*;
import static org.assertj.core.api.Assertions.*;

@ExtendWith(MockitoExtension.class)
class ProcessarEntidadeServiceTest {

    @Mock
    private EntidadeRepository entidadeRepository;

    @Mock
    private EntidadeGateway entidadeGateway;

    @InjectMocks
    private ProcessarEntidadeService service;

    @Test
    void deveProcessarEntidade_quandoGatewayRetornarDados() throws Exception {
        // arrange
        when(entidadeGateway.buscarDados()).thenReturn(Arrays.asList(new EntidadeDominio()));

        // act
        List resultado = service.execute();

        // assert
        assertThat(resultado).hasSize(1);
        verify(entidadeGateway, times(1)).buscarDados();
    }
}

Metodos JapeRepository lancam Exception verificada

JapeRepository (base de todos os repositorios) declara:

V findByPK(K pk) throws Exception;
V save(V entity) throws Exception;

Metodos consulta customizados em interfaces repositorio (ex.: findByCodParceiro, findByIdOrigem) tambem podem declarar throws Exception.

Regra: qualquer metodo teste que chame when(repository.metodo(...)) nesses metodos precisa declarar throws Exception:

@Test
void deveLancarEntityNotFoundException_quandoNaoEncontrado() throws Exception {
    when(repository.findByPK(99)).thenReturn(null); // findByPK throws Exception

    assertThrows(EntityNotFoundException.class, () -> service.execute(99));
}

Mocking estatico (JapeSession, SessionFile)

Use mockito-inline para mockar metodos estaticos do SDK:

import org.mockito.MockedStatic;
import static org.mockito.Mockito.mockStatic;

@Test
void deveExecutar_quandoSessionPropertyAtiva() throws Exception {
    try (MockedStatic japeSessionMock = mockStatic(JapeSession.class)) {
        japeSessionMock.when(() -> JapeSession.getPropertyAsBoolean(anyString(), anyBoolean()))
                .thenReturn(false);

        // act e assert
    }
}

Use try-with-resources pra garantir mock estatico fechado apos teste.

Teste de controller (orquestracao)

Controller so orquestra — nao contem logica de negocio (ver skill controller). Teste verifica delegacao pra service e mapper:

@ExtendWith(MockitoExtension.class)
class PedidoControllerTest {

    @Mock
    private CriarPedidoService criarPedidoService;

    @Mock
    private PedidoRestMapper mapper;

    @InjectMocks
    private PedidoController controller;

    @Test
    void deveDelegarParaServiceEMapper_quandoCriarPedido() {
        // arrange
        CriarPedidoRequest request = new CriarPedidoRequest();
        Pedido pedido = new Pedido();
        PedidoResponse response = new PedidoResponse();

        when(mapper.toPedido(request)).thenReturn(pedido);
        when(criarPedidoService.execute(pedido)).thenReturn(pedido);
        when(mapper.toCriarResponse(pedido)).thenReturn(response);

        // act
        PedidoResponse resultado = controller.criarPedido(request);

        // assert
        assertThat(resultado).isSameAs(response);
        verify(criarPedidoService, times(1)).execute(pedido);
    }
}

Teste de mapper (MapStruct)

Mapper simples (interface, sem uses/@Inject) nao precisa de mock — instancie a implementacao gerada via Mappers.getMapper:

import org.mapstruct.factory.Mappers;

class PedidoRestMapperTest {

    private final PedidoRestMapper mapper = Mappers.getMapper(PedidoRestMapper.class);

    @Test
    void deveMapearCampos_quandoConverterRequest() {
        CriarPedidoRequest request = new CriarPedidoRequest();
        request.setDescricao("Pedido de teste");

        Pedido pedido = mapper.toPedido(request);

        assertThat(pedido.getDescricao()).isEqualTo("Pedido de teste");
    }
}

> Mapper abstract class com @Inject (repository/deps) nao funciona com Mappers.getMapper sem container: instancie a impl gerada (new PedidoMapperImpl()) atribuindo mocks aos campos, ou cubra o mapper via teste do service que o usa.

Armadilha: objetos iguais por Lombok @Data conflitam em stubs

Entidades com @Data geram equals/hashCode de todos campos. Dois objetos criados com new Entidade() (campos nulos) sao iguais pro Mockito. Segundo when(repo.save(obj2)) sobrescreve primeiro when(repo.save(obj1)).

Errado:

Entidade e1 = new Entidade(); // todos os campos nulos
Entidade e2 = new Entidade(); // idem — e1.equals(e2) == true

when(repository.save(e1)).thenReturn(e1);
when(repository.save(e2)).thenThrow(new RuntimeException()); // sobrescreve o anterior!

Correto — usar any() com respostas consecutivas:

Entidade e1 = new Entidade();
Entidade e2 = new Entidade();

when(repository.save(any()))
        .thenReturn(e1)                              // primeira chamada
        .thenThrow(new RuntimeException("erro"));    // segunda chamada

Armadilha: mensagens de excecao com caracteres acentuados

Fontes projeto usam codificacao que pode gerar caracteres corrompidos (?) nos textos excecao runtime. Evite asserções com acentos em assertThat(ex.getMessage()).contains(...):

Fragil (pode falhar por encoding):

assertThat(ex.getMessage()).contains("número da nota");
assertThat(ex.getMessage()).contains("agrônomo");
assertThat(ex.getMessage()).contains("área tratada");

Robusto — usar substring ASCII que aparece na mensagem:

assertThat(ex.getMessage()).contains("da nota");
assertThat(ex.getMessage()).contains("agr");
assertThat(ex.getMessage()).contains("tratada");

Se mensagem vem de wrapper (ex.: "Erro ao criar o pedido. Motivo: %s"), cheque parte invariante ASCII:

assertThat(ex.getMessage()).contains("Motivo:");

Armadilha: UnnecessaryStubbingException em cenarios de erro

MockitoExtension usa modo estrito. Stub configurado mas nao chamado no teste lanca UnnecessaryStubbingException.

Ocorre tipicamente quando metodo auxiliar (helper mock) adiciona stubs que so seriam invocados no caminho feliz, mas teste cobre caminho erro onde execucao para antes.

Errado — stub de getDataCancelamento() nunca chamado quando gateway lanca excecao:

private Pedido pedidoMock() {
    Pedido mock = mock(Pedido.class);
    when(mock.getDataCancelamento()).thenReturn(new Timestamp(...)); // stub extra
    return mock;
}

@Test
void deveLancarIntegrationException_quandoGatewayFalhar() throws Exception {
    Pedido pedido = pedidoMock(); // stub de getDataCancelamento() nao sera usado
    when(gateway.cancel(pedido)).thenThrow(new IntegrationException("erro"));
    // gateway lanca antes de getDataCancelamento() ser chamado -> UnnecessaryStubbingException
}

Correto — use mock() puro quando caminho nao invoca metodos extras:

@Test
void deveLancarIntegrationException_quandoGatewayFalhar() throws Exception {
    Pedido pedido = mock(Pedido.class); // sem stubs desnecessarios
    when(gateway.cancel(pedido)).thenThrow(new IntegrationException("erro"));

    assertThrows(IntegrationException.class, () -> service.execute(pedido));
}

Boas praticas

  • Estrutura AAA: Arrange, Act, Assert.
  • Use @ExtendWith(MockitoExtension.class) pra inicializar mocks.
  • Prefira @InjectMocks + construtor da classe alvo.
  • Valide comportamento e efeitos observaveis. Evite detalhes internos.
  • Um cenario por teste.
  • Dado teste simples e explicito.
  • Declare throws Exception em metodos teste que interajam com repositorios JapeRepository.

O que evitar

  1. Teste com dependencia horario real sem controle.
  2. Assert generico (ex.: so notNull) quando regra exige validacao forte.
  3. Mockar propria classe sob teste.
  4. Teste que cobre varios cenarios nao relacionados no mesmo metodo.
  5. Banco real em teste unitario.
  6. Mockito 5.x em projetos Java 8 — usar 4.11.0.
  7. Asserções mensagem com acentos (ã, ç, ô, ú etc.).
  8. Dois new Entidade() identicos como args de stubs distintos.

Testes de excecao

Quando ha validacao negocio/excecao:

import static org.junit.jupiter.api.Assertions.assertThrows;

@Test
void deveLancarDomainValidationException_quandoEntradaInvalida() throws Exception {
    DomainValidationException ex = assertThrows(
        DomainValidationException.class,
        () -> service.execute(null)
    );

    assertThat(ex.getMessage()).contains("entrada invalida"); // use substring ASCII
}

Execucao local

Raiz projeto:

./gradlew clean test

Ou no modulo:

./gradlew ::test

Fluxo dev Addon Studio: rode testes antes de deployAddon.

Checklist rapido para PR

  • [ ] Existe teste pra nova classe de servico alterada.
  • [ ] Cenario sucesso + ao menos um cenario erro relevante cobertos.
  • [ ] Sem dependencia externa real em teste unitario.
  • [ ] ./gradlew ::test passando local.
  • [ ] throws Exception declarado em metodos que interagem com repositorios.
  • [ ] Stubs sem acentos nas asserções de mensagem.

Skills relacionadas

  • repository — JapeRepository tem quirks — leia antes de mockar (mock via @Mock; estático só JapeSession/SessionFile)
  • dependency-injection — componentes Guice injetam dependências via construtor — facilita mock
  • controller — controllers cobertos por testes
  • entity — fixtures de entidades
  • mapstruct — mappers cobertos

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.