test(logging): optimize logging tests and fix broken tests

This commit is contained in:
qzl
2026-04-01 14:46:47 +08:00
parent d1092df254
commit 640b4d15a3
6 changed files with 316 additions and 87 deletions
+141 -42
View File
@@ -3,7 +3,7 @@ import 'package:social_app/core/logging/log_entry.dart';
void main() {
group('LogEntry', () {
test('toJson should serialize correctly', () {
test('toJson should serialize correctly with all fields', () {
final entry = LogEntry(
timestamp: DateTime(2026, 4, 1, 10, 0, 0),
level: LogLevel.error,
@@ -18,52 +18,17 @@ void main() {
final json = entry.toJson();
expect(json['timestamp'], '2026-04-01T10:00:00.000');
expect(json['level'], 'error');
expect(json['message'], 'Test error');
expect(json['module'], 'test.module');
expect(json['func_name'], 'testFunc');
expect(json['line_no'], 42);
expect(json['error_type'], 'TestError');
expect(json['stack_trace'], 'test stack');
expect(json['extra'], {'key': 'value'});
});
test('toConsoleString should format correctly', () {
final entry = LogEntry(
timestamp: DateTime(2026, 4, 1, 10, 0, 0),
level: LogLevel.debug,
message: 'Test message',
module: 'test.module',
funcName: 'testFunc',
lineNo: 42,
);
final result = entry.toConsoleString();
expect(result, contains('DEBUG'));
expect(result, contains('test.module'));
expect(result, contains('testFunc'));
expect(result, contains('@42'));
expect(result, contains('Test message'));
});
test('toFileString should format correctly', () {
final entry = LogEntry(
timestamp: DateTime(2026, 4, 1, 10, 0, 0),
level: LogLevel.error,
message: 'Test error',
module: 'test.module',
funcName: 'testFunc',
lineNo: 42,
errorType: 'TestError',
stackTrace: 'test stack trace',
);
final result = entry.toFileString();
expect(result, contains('[test.module]'));
expect(result, contains('at testFunc:42'));
expect(result, contains('Test error'));
expect(result, contains('Error: TestError'));
expect(result, contains('StackTrace:'));
expect(result, contains('test stack trace'));
});
test('toJson should omit null fields', () {
final entry = LogEntry(
timestamp: DateTime(2026, 4, 1, 10, 0, 0),
@@ -80,5 +45,139 @@ void main() {
expect(json.containsKey('stack_trace'), false);
expect(json.containsKey('extra'), false);
});
test('toJson should omit extra when empty', () {
final entry = LogEntry(
timestamp: DateTime(2026, 4, 1, 10, 0, 0),
level: LogLevel.info,
message: 'Test',
module: 'test',
extra: {},
);
final json = entry.toJson();
expect(json.containsKey('extra'), false);
});
test('toConsoleString should format debug level correctly', () {
final entry = LogEntry(
timestamp: DateTime(2026, 4, 1, 10, 0, 0),
level: LogLevel.debug,
message: 'Debug message',
module: 'test.module',
funcName: 'testFunc',
lineNo: 42,
);
final result = entry.toConsoleString();
expect(result, contains('DEBUG'));
expect(result, contains('test.module'));
expect(result, contains('testFunc'));
expect(result, contains('@42'));
expect(result, contains('Debug message'));
});
test('toConsoleString should format error level with error type', () {
final entry = LogEntry(
timestamp: DateTime(2026, 4, 1, 10, 0, 0),
level: LogLevel.error,
message: 'Error occurred',
module: 'test.module',
funcName: 'handleError',
lineNo: 100,
errorType: 'SocketException',
);
final result = entry.toConsoleString();
expect(result, contains('ERROR'));
expect(result, contains('[SocketException]'));
expect(result, contains('handleError'));
expect(result, contains('@100'));
});
test('toConsoleString should format without location when null', () {
final entry = LogEntry(
timestamp: DateTime(2026, 4, 1, 10, 0, 0),
level: LogLevel.info,
message: 'Simple message',
module: 'simple.module',
);
final result = entry.toConsoleString();
expect(result, contains('INFO'));
expect(result, contains('simple.module'));
expect(result, contains('Simple message'));
});
test('toFileString should format correctly with all fields', () {
final entry = LogEntry(
timestamp: DateTime(2026, 4, 1, 10, 0, 0),
level: LogLevel.error,
message: 'Test error',
module: 'test.module',
funcName: 'testFunc',
lineNo: 42,
errorType: 'TestError',
stackTrace: 'test stack trace',
extra: {'key': 'value'},
);
final result = entry.toFileString();
expect(result, contains('[test.module]'));
expect(result, contains('at testFunc:42'));
expect(result, contains('Test error'));
expect(result, contains('Error: TestError'));
expect(result, contains('StackTrace:'));
expect(result, contains('test stack trace'));
expect(result, contains('Extra:'));
});
test('toFileString should format with only funcName (no lineNo)', () {
final entry = LogEntry(
timestamp: DateTime(2026, 4, 1, 10, 0, 0),
level: LogLevel.warning,
message: 'Warning message',
module: 'warn.module',
funcName: 'warningFunc',
);
final result = entry.toFileString();
expect(result, contains('WARNING [warn.module]'));
expect(result, contains('at warningFunc'));
expect(result, isNot(contains(':42')));
});
test('toFileString should format with only lineNo (no funcName)', () {
final entry = LogEntry(
timestamp: DateTime(2026, 4, 1, 10, 0, 0),
level: LogLevel.warning,
message: 'Warning at line',
module: 'warn.module',
lineNo: 99,
);
final result = entry.toFileString();
expect(result, contains('at :99'));
});
test('LogLevel ordering is correct', () {
expect(LogLevel.debug.index, lessThan(LogLevel.info.index));
expect(LogLevel.info.index, lessThan(LogLevel.warning.index));
expect(LogLevel.warning.index, lessThan(LogLevel.error.index));
});
test('LogLevel names are lowercase', () {
expect(LogLevel.debug.name, 'debug');
expect(LogLevel.info.name, 'info');
expect(LogLevel.warning.name, 'warning');
expect(LogLevel.error.name, 'error');
});
});
}
@@ -0,0 +1,94 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:social_app/core/logging/log_config.dart';
import 'package:social_app/core/logging/log_entry.dart';
import 'package:social_app/core/logging/log_service.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('LogService', () {
test('LogConfig.forDebug creates correct config', () {
final config = LogConfig.forDebug();
expect(config.minLevel, LogLevel.debug);
expect(config.output, LogOutput.console);
});
test('LogConfig.forRelease creates correct config', () {
final config = LogConfig.forRelease();
expect(config.minLevel, LogLevel.warning);
expect(config.output, LogOutput.file);
expect(config.logFileName, 'app.log');
expect(config.logDir, 'logs');
});
test('LogConfig default values are correct', () {
const config = LogConfig();
expect(config.minLevel, LogLevel.debug);
expect(config.output, LogOutput.console);
expect(config.logFileName, 'app.log');
expect(config.logDir, 'logs');
});
test('LogService with console output logs all levels', () async {
final service = await LogService.create(
config: const LogConfig(minLevel: LogLevel.debug),
);
service.debug(message: 'debug msg', module: 'test');
service.info(message: 'info msg', module: 'test', extra: {'a': 1});
service.warning(message: 'warn msg', module: 'test', extra: {'a': 1});
service.error(
message: 'error msg',
error: Exception('test'),
stackTrace: StackTrace.current,
module: 'test',
);
service.flush();
});
test('LogService filters by minLevel - info', () async {
final service = await LogService.create(
config: const LogConfig(minLevel: LogLevel.info),
);
service.debug(message: 'debug msg', module: 'test');
service.flush();
});
test('error method extracts error type from exception', () async {
final service = await LogService.create(
config: const LogConfig(minLevel: LogLevel.error),
);
try {
throw ArgumentError('test error');
} catch (e, st) {
service.error(
message: 'Test error occurred',
error: e,
stackTrace: st,
module: 'test.module',
extra: {'test': true},
);
}
service.flush();
});
test('debug method captures StackTrace.current', () async {
final service = await LogService.create(
config: const LogConfig(minLevel: LogLevel.debug),
);
service.debug(message: 'Debug with location', module: 'test.location');
service.flush();
});
});
}