Skip to content

Commit 92da20c

Browse files
committed
test: Add comprehensive test coverage for DefaultChatClient and DefaultChatClientBuilder
Co-authored-by: Oleksandr Klymenko <[email protected]> Signed-off-by: Oleksandr Klymenko <[email protected]>
1 parent c893629 commit 92da20c

File tree

2 files changed

+157
-22
lines changed

2 files changed

+157
-22
lines changed

spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/DefaultChatClientBuilderTests.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,61 @@ void whenTemplateRendererIsNullThenThrows() {
102102
.hasMessage("templateRenderer cannot be null");
103103
}
104104

105+
@Test
106+
void whenCloneBuilderThenModifyingOriginalDoesNotAffectClone() {
107+
var chatModel = mock(ChatModel.class);
108+
var originalBuilder = new DefaultChatClientBuilder(chatModel);
109+
originalBuilder.defaultSystem("original system");
110+
originalBuilder.defaultUser("original user");
111+
112+
var clonedBuilder = (DefaultChatClientBuilder) originalBuilder.clone();
113+
114+
// Modify original
115+
originalBuilder.defaultSystem("modified system");
116+
originalBuilder.defaultUser("modified user");
117+
118+
var clonedRequest = (DefaultChatClient.DefaultChatClientRequestSpec) ReflectionTestUtils.getField(clonedBuilder,
119+
"defaultRequest");
120+
121+
assertThat(clonedRequest.getSystemText()).isEqualTo("original system");
122+
assertThat(clonedRequest.getUserText()).isEqualTo("original user");
123+
}
124+
125+
@Test
126+
void whenBuildChatClientThenReturnsValidInstance() {
127+
var chatModel = mock(ChatModel.class);
128+
var builder = new DefaultChatClientBuilder(chatModel);
129+
130+
var chatClient = builder.build();
131+
132+
assertThat(chatClient).isNotNull();
133+
assertThat(chatClient).isInstanceOf(DefaultChatClient.class);
134+
}
135+
136+
@Test
137+
void whenOverridingSystemPromptThenLatestValueIsUsed() {
138+
var chatModel = mock(ChatModel.class);
139+
var builder = new DefaultChatClientBuilder(chatModel);
140+
141+
builder.defaultSystem("first system prompt");
142+
builder.defaultSystem("second system prompt");
143+
144+
var defaultRequest = (DefaultChatClient.DefaultChatClientRequestSpec) ReflectionTestUtils.getField(builder,
145+
"defaultRequest");
146+
assertThat(defaultRequest.getSystemText()).isEqualTo("second system prompt");
147+
}
148+
149+
@Test
150+
void whenOverridingUserPromptThenLatestValueIsUsed() {
151+
var chatModel = mock(ChatModel.class);
152+
var builder = new DefaultChatClientBuilder(chatModel);
153+
154+
builder.defaultUser("first user prompt");
155+
builder.defaultUser("second user prompt");
156+
157+
var defaultRequest = (DefaultChatClient.DefaultChatClientRequestSpec) ReflectionTestUtils.getField(builder,
158+
"defaultRequest");
159+
assertThat(defaultRequest.getUserText()).isEqualTo("second user prompt");
160+
}
161+
105162
}

spring-ai-client-chat/src/test/java/org/springframework/ai/chat/client/DefaultChatClientTests.java

Lines changed: 100 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1683,28 +1683,6 @@ void whenFunctionNameIsEmptyThenThrow() {
16831683
.build())).isInstanceOf(IllegalArgumentException.class).hasMessage("name cannot be null or empty");
16841684
}
16851685

1686-
@Test
1687-
@Disabled("This fails now as the FunctionToolCallback description is allowed to be empty")
1688-
void whenFunctionDescriptionIsNullThenThrow() {
1689-
ChatClient chatClient = new DefaultChatClientBuilder(mock(ChatModel.class)).build();
1690-
ChatClient.ChatClientRequestSpec spec = chatClient.prompt();
1691-
assertThatThrownBy(() -> spec.toolCallbacks(FunctionToolCallback.builder("name", input -> "hello")
1692-
.description(null)
1693-
.inputType(String.class)
1694-
.build())).isInstanceOf(IllegalArgumentException.class).hasMessage("Description must not be empty");
1695-
}
1696-
1697-
@Test
1698-
@Disabled("This fails now as the FunctionToolCallback description is allowed to be empty")
1699-
void whenFunctionDescriptionIsEmptyThenThrow() {
1700-
ChatClient chatClient = new DefaultChatClientBuilder(mock(ChatModel.class)).build();
1701-
ChatClient.ChatClientRequestSpec spec = chatClient.prompt();
1702-
assertThatThrownBy(() -> spec.toolCallbacks(
1703-
FunctionToolCallback.builder("name", input -> "hello").description("").inputType(String.class).build()))
1704-
.isInstanceOf(IllegalArgumentException.class)
1705-
.hasMessage("Description must not be empty");
1706-
}
1707-
17081686
@Test
17091687
void whenFunctionThenReturn() {
17101688
ChatClient chatClient = new DefaultChatClientBuilder(mock(ChatModel.class)).build();
@@ -2100,4 +2078,104 @@ void whenUserConsumerWithoutUserTextThenReturn() {
21002078
record Person(String name) {
21012079
}
21022080

2081+
@Test
2082+
void whenDefaultChatClientBuilderWithObservationRegistryThenReturn() {
2083+
var chatModel = mock(ChatModel.class);
2084+
var observationRegistry = mock(ObservationRegistry.class);
2085+
var observationConvention = mock(ChatClientObservationConvention.class);
2086+
2087+
var builder = new DefaultChatClientBuilder(chatModel, observationRegistry, observationConvention);
2088+
2089+
assertThat(builder).isNotNull();
2090+
}
2091+
2092+
@Test
2093+
void whenPromptWithSystemUserAndOptionsThenReturn() {
2094+
ChatClient chatClient = new DefaultChatClientBuilder(mock(ChatModel.class)).build();
2095+
ChatOptions options = ChatOptions.builder().build();
2096+
2097+
DefaultChatClient.DefaultChatClientRequestSpec spec = (DefaultChatClient.DefaultChatClientRequestSpec) chatClient
2098+
.prompt()
2099+
.system("instructions")
2100+
.user("question")
2101+
.options(options);
2102+
2103+
assertThat(spec.getSystemText()).isEqualTo("instructions");
2104+
assertThat(spec.getUserText()).isEqualTo("question");
2105+
assertThat(spec.getChatOptions()).isEqualTo(options);
2106+
}
2107+
2108+
@Test
2109+
void whenToolNamesWithEmptyArrayThenReturn() {
2110+
ChatClient chatClient = new DefaultChatClientBuilder(mock(ChatModel.class)).build();
2111+
ChatClient.ChatClientRequestSpec spec = chatClient.prompt().toolNames();
2112+
2113+
DefaultChatClient.DefaultChatClientRequestSpec defaultSpec = (DefaultChatClient.DefaultChatClientRequestSpec) spec;
2114+
assertThat(defaultSpec.getToolNames()).isEmpty();
2115+
}
2116+
2117+
@Test
2118+
void whenUserParamsWithEmptyMapThenReturn() {
2119+
DefaultChatClient.DefaultPromptUserSpec spec = new DefaultChatClient.DefaultPromptUserSpec();
2120+
spec = (DefaultChatClient.DefaultPromptUserSpec) spec.params(Map.of());
2121+
assertThat(spec.params()).isEmpty();
2122+
}
2123+
2124+
@Test
2125+
void whenSystemParamsWithEmptyMapThenReturn() {
2126+
DefaultChatClient.DefaultPromptSystemSpec spec = new DefaultChatClient.DefaultPromptSystemSpec();
2127+
spec = (DefaultChatClient.DefaultPromptSystemSpec) spec.params(Map.of());
2128+
assertThat(spec.params()).isEmpty();
2129+
}
2130+
2131+
@Test
2132+
void whenAdvisorSpecWithMultipleParamsThenAllStored() {
2133+
DefaultChatClient.DefaultAdvisorSpec spec = new DefaultChatClient.DefaultAdvisorSpec();
2134+
spec = (DefaultChatClient.DefaultAdvisorSpec) spec.param("param1", "value1")
2135+
.param("param2", "value2")
2136+
.param("param3", "value3");
2137+
2138+
assertThat(spec.getParams()).containsEntry("param1", "value1")
2139+
.containsEntry("param2", "value2")
2140+
.containsEntry("param3", "value3");
2141+
}
2142+
2143+
@Test
2144+
void whenMessagesWithEmptyListThenReturn() {
2145+
ChatClient chatClient = new DefaultChatClientBuilder(mock(ChatModel.class)).build();
2146+
ChatClient.ChatClientRequestSpec spec = chatClient.prompt().messages(List.of());
2147+
2148+
DefaultChatClient.DefaultChatClientRequestSpec defaultSpec = (DefaultChatClient.DefaultChatClientRequestSpec) spec;
2149+
// Messages should not be modified from original state
2150+
assertThat(defaultSpec.getMessages()).isNotNull();
2151+
}
2152+
2153+
@Test
2154+
void whenMutateBuilderThenReturnsSameType() {
2155+
ChatClient chatClient = new DefaultChatClientBuilder(mock(ChatModel.class)).build();
2156+
ChatClient.Builder mutatedBuilder = chatClient.mutate();
2157+
2158+
assertThat(mutatedBuilder).isInstanceOf(DefaultChatClientBuilder.class);
2159+
}
2160+
2161+
@Test
2162+
void whenSystemConsumerWithNullParamValueThenThrow() {
2163+
ChatClient chatClient = new DefaultChatClientBuilder(mock(ChatModel.class)).build();
2164+
ChatClient.ChatClientRequestSpec spec = chatClient.prompt();
2165+
2166+
assertThatThrownBy(() -> spec.system(system -> system.param("key", null)))
2167+
.isInstanceOf(IllegalArgumentException.class)
2168+
.hasMessage("value cannot be null");
2169+
}
2170+
2171+
@Test
2172+
void whenUserConsumerWithNullParamValueThenThrow() {
2173+
ChatClient chatClient = new DefaultChatClientBuilder(mock(ChatModel.class)).build();
2174+
ChatClient.ChatClientRequestSpec spec = chatClient.prompt();
2175+
2176+
assertThatThrownBy(() -> spec.user(user -> user.param("key", null)))
2177+
.isInstanceOf(IllegalArgumentException.class)
2178+
.hasMessage("value cannot be null");
2179+
}
2180+
21032181
}

0 commit comments

Comments
 (0)