Pamiętacie wpis o najlepszych praktykach REST’owych? Jedną z wyszczególnionych tam praktyk było dokumentowanie naszego API. Wymieniłem tam także kilka najpopularniejszych rozwiązań. Jedno z nich, czyli Swagger opisałem już na blogu w artykule #10 Spring Boot - Swagger2 - dokumentujemy API. Dziś czas na kolejne podejście do dokumentacji, tym razem od strony testów. Test Driven Documentation jest techniką, która polega na tworzeniu dokumentacji w oparciu o testy.
Jak napisałem we wstępie, Spring Rest Docs wykorzystuje podejście, w którym pisanie dokumentacji odbywa się poprzez wykorzystanie testów. W testach tworzone są snippety, które następnie łączone są w jeden plik korzystając ze składni ASCIIDoc’a. Cała dokumentacja frameworku Spring napisana jest przy jej użyciu. ASCIIDoc przetwarza tekst na HTML. Spring Rest Docs wspiera:
- Spring MVC Test - wykorzystany w przykładzie
- REST Assured
1. Maven
Standardowo zaczynamy od dodania zależności do Maven’a:
Oraz musimy skonfigurować proces budowania dokumentacji:
2. Domena
Na szybko stwórzmy sobie encję Todo, która będzie dostępna pod endpointem /todos.
@Data
@AllArgsConstructor
public class Todo {
@Id
@GeneratedValue
private Long id;
private String title;
private String description;
}
Teraz dodajmy controller:
@RestController
@RequestMapping(“/todos”)
class TodoController {
@GetMapping
@ResponseStatus(value = HttpStatus.OK)
Todo getTodoByTitle(@RequestParam(value = "title", required = true) String title){
return new Todo(1l, "TDD", "Description");
}
}
3. Dokumentacja
Możemy zacząć pisanie testów! Jeśli zdecydowaliśmy się korzystać ze Spring MVC Test musimy zdefiniować @Rule dla klasy JUnitRestDocumentation, która w konstruktorze przyjmuje folder, gdzie znajdą się wygenerowane snippety (snippety to elementy generowane przez Spring Rest Docs, które umieszczamy potem w naszej dokumentacji):
@Rule
public JUnitRestDocumentation documentation = new JUnitRestDocumentation(“target/generated-snippets”);
Musimy teraz poinstruować nasz test, aby generował dokumentację:
@RunWith(SpringRunner.class)
@SpringBootTest
public class TodoDocumentation {
@Rule
public JUnitRestDocumentation documentation = new JUnitRestDocumentation("target/generated-snippets");
@Autowired
private WebApplicationContext context;
@Autowired
private TodoRepository todoRepository;
private MockMvc mockMvc;
@Before
public void setUp() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
.apply(documentationConfiguration(this.documentation))
.build();
}
@Test
public void shouldReturnTodo() throws Exception {
todoRepository.save(new Todo("TDD", "CodeCouple"));
this.mockMvc.perform(
get("/todos")
.param("title", "TDD")
.accept(MediaType.APPLICATION\_JSON))
.andExpect(status().isOk())
.andDo(document("todos",
responseFields(
fieldWithPath("id").description("Todo ID"),
fieldWithPath("title").description("Todo title"),
fieldWithPath("description").description("Todo description")),
requestParameters(
parameterWithName("title").description("Todo title"))));
}
}
Ważna część dla nas zaczyna się od statycznej metody document. Tam umieszczamy testy odpowiedzialne za generowanie dokumentacji. Metoda responseFields sprawdza, czy w odpowiedzi otrzymaliśmy pola: id, title, description. Jeśli tak, to zostaną one udokumentowane wraz z opisem zawartym w description. Kolejna metoda requestParameters służy do testu i opisu parametrów zawartych w naszym URI. Oczywiście istnieje dużo więcej metod.
Aby stworzyć plik HTML z dokumentacją należy dodać wzorcowy plik ASIIDOC’a, w moim przypadku dodałem plik manual.adoc z treścią poniżej. Domyślną ścieżką na ten plik jest src/main/asciidoc. Można tę ścieżkę zmienić w pluginie, należy w sekcji build dodać wpis <sourceDirectory>your/path/here</sourceDirectory>
= Todos API Reference
CodeCouple.pl - Version 1.0.1;
:doctype: book
:icons: font
:source-highlighter: highlightjs
:toc: left
:toclevels: 4
:sectlinks:
[[headers]]
== Headers
Curl-request in CodeCouple.pl:
include::{snippets}/todos/curl-request.adoc[]
include::{snippets}/todos/http-request.adoc[]
include::{snippets}/todos/http-response.adoc[]
include::{snippets}/todos/response-fields.adoc[]
include::{snippets}/todos/request-parameters.adoc[]
Teraz w pierwszej kolejności uruchamiamy test, który wygeneruje nam do folderu target/generated-snippets snippety. Następnie odpalamy install w Mavenie. W folderze target/generated-docs powinien dodać nam się plik manual.html (ma taką samą nazwę jak nasz plik z ASCIIDoc’a). Ścieżkę, gdzie generować ma się dokumentacja możemy ustawić w sekcji build, należy dodać wpis <outputDirectory>your/path/here</outputDirectory>
3.1 Automatyczne budowanie
Jeśli chcemy mieć zautomatyzowany proces budowania wystarczy dodać poniższy plugin. Od teraz dla wszystkich klas z Documetation w nazwie generowana będzie dokumentacja przy budowaniu Mavenowego artefaktu.
<``plugin``>
<``groupId``>org.apache.maven.plugins</``groupId``>
<``artifactId``>maven-surefire-plugin</``artifactId``>
<``configuration``>
<``includes``>
<``include``>**/*Documentation.java</``include``>
</``includes``>
</``configuration``>
</``plugin``>
4. Wynik
Wynikiem działania jest bardzo dobrze wyglądający HTML: 
5. Github
Całość jak zawsze na GitHubie.
