### Question:
MainViewModel implements ViewModel { void search() { Consumer<Error> errorHandler = err -> error.set(err.getMessage()); final List<Book> result = libraryService.search(searchString.get(), errorHandler); books.clear(); books.addAll(result .stream() .map(bookWithoutDescription -> libraryService.showDetails(bookWithoutDescription, errorHandler)) .map(BookListItemViewModel::new) .collect(Collectors.toList())); } MainViewModel(LibraryService libraryService); Command getSearchCommand(); StringProperty searchStringProperty(); StringProperty bookTitleProperty(); StringProperty bookAuthorProperty(); StringProperty bookDescriptionProperty(); ObservableList<BookListItemViewModel> booksProperty(); ObjectProperty<BookListItemViewModel> selectedBookProperty(); StringProperty errorProperty();  }### Answer:
@Test public void testSearch() { assertThat(viewModel.booksProperty()).isEmpty(); assertThat(viewModel.searchStringProperty()).hasValue(""); Book book1 = createBook("a book starting with a", "some author", null); Book book1WithDescription = createBook("a book starting with a", "some author", "some description 1"); Book book2 = createBook("another book starting with a", "some author", null); Book book2WithDescription = createBook("another book starting with a", "some author", "some description 2"); Book book3 = createBook("book starting with b", "some author", null); Book book3WithDescription = createBook("book starting with b", "some author", "some description 3"); when(libraryService.search(eq("a"), any())).thenReturn(Arrays.asList(book1, book2)); when(libraryService.search(eq("b"), any())).thenReturn(Arrays.asList(book3)); when(libraryService.search(eq(""), any())).thenReturn(Collections.emptyList()); when(libraryService.showDetails(eq(book1), any())).thenReturn(book1WithDescription); when(libraryService.showDetails(eq(book2), any())).thenReturn(book2WithDescription); when(libraryService.showDetails(eq(book3), any())).thenReturn(book3WithDescription); viewModel.searchStringProperty().set("a"); viewModel.search(); assertThat(viewModel.booksProperty()).hasSize(2); assertThat(viewModel.booksProperty().get(0).getBook().getTitle()).isEqualTo("a book starting with a"); assertThat(viewModel.booksProperty().get(0).getBook().getDesc()).isEqualTo("some description 1"); assertThat(viewModel.booksProperty().get(1).getBook().getTitle()).isEqualTo("another book starting with a"); assertThat(viewModel.booksProperty().get(1).getBook().getDesc()).isEqualTo("some description 2"); viewModel.searchStringProperty().set("b"); viewModel.search(); assertThat(viewModel.booksProperty()).hasSize(1); assertThat(viewModel.booksProperty().get(0).getBook().getTitle()).isEqualTo("book starting with b"); assertThat(viewModel.booksProperty().get(0).getBook().getDesc()).isEqualTo("some description 3"); viewModel.searchStringProperty().set(""); viewModel.search(); assertThat(viewModel.booksProperty()).isEmpty(); }