Skip to content

Commit

Permalink
add unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
Ida631 committed Dec 6, 2024
1 parent 4474ae7 commit 16bc39a
Show file tree
Hide file tree
Showing 11 changed files with 167 additions and 17 deletions.
4 changes: 2 additions & 2 deletions lib/app/injection_container.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ void initInjection() {
sl.registerFactory<UpdatePasswordViewModel>(() => UpdatePasswordViewModel(authUseCase: sl()));

// Use Cases
sl.registerLazySingleton<ChatUseCase>(() => ChatUseCase(chatRepository: sl()));
sl.registerLazySingleton<ChatUseCase>(() => ChatUseCaseImpl(chatRepository: sl()));

sl.registerLazySingleton<ChatSessionUseCase>(() => ChatSessionUseCase(repository: sl()));
sl.registerLazySingleton<ChatSessionUseCase>(() => ChatSessionUseCaseImpl(repository: sl()));

sl.registerLazySingleton<FunctionToolsUseCase>(() => FunctionToolsUseCase());

Expand Down
9 changes: 2 additions & 7 deletions lib/presentation/chat/viewModels/chat_view_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,7 @@ class ChatViewModel extends ChangeNotifier {
_chatSessionUseCase = chatSessionUseCase,
_functionToolsUseCase = functionToolsUseCase,
_authUseCase = authUseCase,
_userUserCase = userUserCase {
checkAuthStatus();
initializeChatSessions();
}


_userUserCase = userUserCase;

Future<void> fetchAuthSessionNew() async {
try {
Expand Down Expand Up @@ -96,7 +91,7 @@ class ChatViewModel extends ChangeNotifier {
}

// Initialize session if no sessions exist
void initializeChatSessions() async {
Future<void> initializeChatSessions() async {
sessions = await _chatSessionUseCase.getAllSessions();
if (sessions.isEmpty) {
addNewSession();
Expand Down
2 changes: 1 addition & 1 deletion lib/presentation/chat/views/chat_message_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class _ChatMessageListState extends State<ChatMessageList> {
child: Icon(
Icons.chat_bubble_outline,
size: 80,
color: Colors.grey,
color: Colors.blueGrey,
),
),
Text(
Expand Down
12 changes: 9 additions & 3 deletions lib/presentation/chat/views/chat_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class _ChatScreenState extends State<ChatScreen>
void initState() {
super.initState();
viewModel = Provider.of<ChatViewModel>(context, listen: false);
_initializeChatSessions();
_fetchAuthSession();
}

Expand All @@ -34,6 +35,11 @@ class _ChatScreenState extends State<ChatScreen>
setState(() {});
}

Future<void> _initializeChatSessions() async {
await viewModel.initializeChatSessions();
setState(() {});
}

@override
Widget build(BuildContext context) {
super.build(context); // Ensure AutomaticKeepAliveClientMixin works
Expand All @@ -48,7 +54,7 @@ class _ChatScreenState extends State<ChatScreen>
if (!viewModel.isLoggedIn) {
// If the user is not logged in, show login icon
return IconButton(
icon: const Icon(Icons.login),
icon: const Icon(Icons.manage_accounts),
color: Colors.white,
tooltip: "Sign In",
onPressed: () async {
Expand Down Expand Up @@ -124,7 +130,7 @@ class _ChatScreenState extends State<ChatScreen>
const Icon(
Icons.chat_bubble_outline,
size: 100,
color: Colors.blueAccent,
color: Colors.blueGrey,
),
const SizedBox(height: 20),
const Text(
Expand All @@ -150,7 +156,7 @@ class _ChatScreenState extends State<ChatScreen>
setState(() {}); // Trigger UI rebuild
}
},
icon: const Icon(Icons.login, size: 20),
icon: const Icon(Icons.manage_accounts, size: 22),
label: const Text(
"Login to Chat",
style: TextStyle(fontSize: 16),
Expand Down
18 changes: 18 additions & 0 deletions packages/domain/lib/mocks/chat_usecase_mock.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@


import 'package:mockito/mockito.dart';

import '../entities/chat_session.dart';
import '../entities/message.dart';
import '../usecases/chat_usecase.dart';

class MockChatUseCase extends Mock implements ChatUseCase {
@override
Stream<Message> sendMessage(Message newMessage, ChatSession session) {
return super.noSuchMethod(
Invocation.method(#sendMessage, [newMessage, session]),
returnValue: Stream<Message>.empty(), // Provide a default empty Stream
returnValueForMissingStub: Stream<Message>.empty(),
);
}
}
17 changes: 17 additions & 0 deletions packages/domain/lib/mocks/chatsession_usecase_mock.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@


import 'package:mockito/mockito.dart';

import '../entities/chat_session.dart';
import '../usecases/chat_session_usecase.dart';

class MockChatSessionUseCase extends Mock implements ChatSessionUseCase {
@override
Future<List<ChatSession>> getAllSessions() {
return super.noSuchMethod(
Invocation.method(#getAllSessions, []),
returnValue: Future.value(<ChatSession>[]), // Return an empty Future<List<ChatSession>>
returnValueForMissingStub: Future.value(<ChatSession>[]), // Provide a default empty Future
);
}
}
6 changes: 6 additions & 0 deletions packages/domain/lib/mocks/functiontool_usecase_mock.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import 'package:mockito/mockito.dart';
import '../usecases/function_tools_usecase.dart';

class MockFunctionToolsUseCase extends Mock implements FunctionToolsUseCase {

}
15 changes: 13 additions & 2 deletions packages/domain/lib/usecases/chat_session_usecase.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,21 @@ import '../entities/chat_session.dart';
import '../entities/message.dart';
import '../repositories_abstract/chat_session_repository.dart';

class ChatSessionUseCase {
abstract class ChatSessionUseCase {
Future<List<ChatSession>> getAllSessions();
Future<void> saveSession(ChatSession session);
Future<void> deleteSession(String sessionId);
ChatSession createNewSession();
void addMessageToSession(ChatSession session, Message message);
bool isLastMessageAssistInSession(ChatSession session);
void updateLastAssistantMessage(ChatSession session, Message message);
}


class ChatSessionUseCaseImpl implements ChatSessionUseCase {
final ChatSessionRepository repository;

ChatSessionUseCase({required this.repository});
ChatSessionUseCaseImpl({required this.repository});

Future<List<ChatSession>> getAllSessions() async {
return repository.getAllSessions();
Expand Down
8 changes: 6 additions & 2 deletions packages/domain/lib/usecases/chat_usecase.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import 'package:domain/domain.dart';

class ChatUseCase {
abstract class ChatUseCase {
Stream<Message> sendMessage(Message newMessage, ChatSession session);
}

class ChatUseCaseImpl implements ChatUseCase {
final ChatRepository chatRepository;

ChatUseCase({required this.chatRepository});
ChatUseCaseImpl({required this.chatRepository});

final Message systemMessage = Message(
role: "system",
Expand Down
92 changes: 92 additions & 0 deletions test/chat_view_model_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import 'package:domain/entities/user.dart';
import 'package:domain/mocks/auth_usecase_mock.dart';
import 'package:domain/mocks/user_usecase_mock.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:swiftcomp/presentation/chat/viewModels/chat_view_model.dart';
import 'package:domain/mocks/chat_usecase_mock.dart';
import 'package:domain/mocks/chatsession_usecase_mock.dart';
import 'package:domain/mocks/functiontool_usecase_mock.dart';

void main() {
group('ChatViewModel Tests', () {
late MockChatUseCase mockChatUseCase;
late MockChatSessionUseCase mockChatSessionUseCase;
late MockFunctionToolsUseCase mockFunctionToolsUseCase;
late MockAuthUseCase mockAuthUseCase;
late MockUserUseCase mockUserUseCase;
late ChatViewModel chatViewModel;

setUp(() {
// Initialize the mocks and view model before each test
mockAuthUseCase = MockAuthUseCase();
mockUserUseCase = MockUserUseCase();
mockChatUseCase = MockChatUseCase();
mockChatSessionUseCase = MockChatSessionUseCase();
mockFunctionToolsUseCase = MockFunctionToolsUseCase();
chatViewModel = ChatViewModel(
chatUseCase: mockChatUseCase,
authUseCase: mockAuthUseCase,
userUserCase: mockUserUseCase,
chatSessionUseCase: mockChatSessionUseCase,
functionToolsUseCase: mockFunctionToolsUseCase,
);
});

tearDown(() {
// Clean up resources or reset mock state after each test
reset(mockAuthUseCase);
reset(mockUserUseCase);
reset(mockChatUseCase);
reset(mockChatSessionUseCase);
reset(mockFunctionToolsUseCase);
});

group('fetchAuthSessionNew', () {
test('fetchAuthSessionNew sets isLoggedIn to true and fetches user when logged in', () async {
// Arrange
when(mockAuthUseCase.isLoggedIn()).thenAnswer((_) async => true);
final mockUser =
User(name: 'Test User', email: '[email protected]', avatarUrl: 'test-avatar.png');
when(mockUserUseCase.fetchMe()).thenAnswer((_) async => mockUser);

// Act
await chatViewModel.fetchAuthSessionNew();

// Assert
expect(chatViewModel.isLoggedIn, true);
expect(chatViewModel.user, mockUser);
verify(mockAuthUseCase.isLoggedIn()).called(1);
verify(mockUserUseCase.fetchMe()).called(1);
});

test('fetchAuthSessionNew handles exception and resets state', () async {
// Arrange
when(mockAuthUseCase.isLoggedIn()).thenThrow(Exception('Auth error'));

// Act
await chatViewModel.fetchAuthSessionNew();

// Assert
expect(chatViewModel.isLoggedIn, false);
expect(chatViewModel.user, null);
verify(mockAuthUseCase.isLoggedIn()).called(1);
});

test('fetchAuthSessionNew sets isLoggedIn to false and user to null when not logged in',
() async {
// Arrange
when(mockAuthUseCase.isLoggedIn()).thenAnswer((_) async => false);

// Act
await chatViewModel.fetchAuthSessionNew();

// Assert
expect(chatViewModel.isLoggedIn, false);
expect(chatViewModel.user, null);
verify(mockAuthUseCase.isLoggedIn()).called(1);
verifyNever(mockUserUseCase.fetchMe());
});
});
});
}
1 change: 1 addition & 0 deletions test/login_view_model_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ void main() {
// Clean up resources or reset mock state after each test
reset(mockAuthUseCase);
reset(mockAppleSignInService);
reset(mockGoogleSignInService);
});

group('togglePasswordVisibility', () {
Expand Down

0 comments on commit 16bc39a

Please sign in to comment.