nebula-logger-testing-your-code について
nebula-logger-testing-your-codeは、ApexまたはLWCでNebula Loggerを使う開発者向けのテストスキルです。バッファ内のログ確認、保存済みレコードの検証、テスト中の保存制御、LWCテストでのロガー呼び出しのモックを扱います。
主な機能
- 01バッファ内ログ件数のアサート
- 02保存済みログレコードの検証
- 03保存の制御とバッファの消去
- 04非同期テストでのイベント配信への対応
- 05LWCのロガー呼び出しをモックして検証
活用シーン
- 01ログを出力するApexコードのテスト
- 02保存済みメッセージやシナリオの確認
- 03テスト中のログ永続化の抑止
- 04LWCテストでのログ引数の検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jongpie/ nebulalogger --skill nebula-logger-testing-your-codeインストール後、Claude Code で/nebula-logger-testing-your-codeを入力して読み込まれたか確認します。
詳細
Nebula Logger を使用するコードのテスト
このスキルは、独自の Apex または LWC コードから Logger.info(...)、Logger.error(...) などを呼び出し、テストで適切にログが記録されることを確認したい開発者向けです。global の Nebula Logger API のみを使用するため、組織にアンロック版パッケージとマネージドパッケージのどちらがインストールされていても、同じ手法を利用できます。
バッファーモデル
Nebula Logger は、トランザクション中にログエントリーをメモリにバッファリングします。Logger.saveLog() は、バッファー内のエントリーを保存パス(プラットフォームイベント、キュー可能、REST、または同期 DML)に移動します。保存方法の選択については、nebula-logger-instrumentation を参照してください。
テストでは、バッファーが観測ポイントになります。エントリーを追加し、saveLog() の前にバッファーサイズを確認した後、saveLog() を呼び出して結果のレコードをクエリするか、永続化せずに破棄するため flushBuffer() を呼び出せます。3 つの API はすべて global です。
保存前にバッファーをアサートする
Logger.getBufferSize() は、現在バッファーに格納されているエントリー数を返します。永続化せずに、コードが想定したエントリーを追加したことを確認するために使用できます。
@IsTest
static void it_should_log_a_warning_when_credit_check_fails() {
Account account = new Account(Name = 'Test Account');
insert account;
System.Test.startTest();
new CreditCheckService().evaluate(account.Id);
System.Test.stopTest();
System.Assert.areEqual(1, Logger.getBufferSize(), 'Expected exactly one entry buffered');
}
getBufferSize() は saveLog() が実行される前に呼び出されるため、プラットフォームイベントの公開を待たずにアサーションできます。
保存後に永続化されたレコードをアサートする
メッセージのテキスト、ログレベル、関連レコード、またはシナリオをアサートする必要がある場合は、ログを保存して永続化されたレコードをクエリします。ログ管理側のカスタムオブジェクト一式は次のとおりです。
Log__c- ロギングトランザクションごとに 1 つのレコード。LogEntry__c-Logger.info(...)/.error(...)などの呼び出しごとに 1 つのレコード。LogEntryTag__c- タグが適用されたときの、LogEntry__cとLoggerTag__c間の中間オブジェクト。LoggerScenario__c- トランザクション間で使用された、Logger.setScenario(...)の一意な値をそれぞれ記録します。LoggerTag__c-LogEntryTag__cが参照するタグカタログ。
デフォルトの EVENT_BUS 保存方法では、System.Test.stopTest() 中にプラットフォームイベントが発火し、上記すべてのオブジェクトにデータが格納されます。
System.Test.getEventBus().deliver() も必要な場合
System.Test.stopTest() が配信するのは、stopTest の境界より前にキューに追加されたプラットフォームイベントのみです。stopTest 自体がフラッシュする非同期処理中に公開された LogEntryEvent__e レコードについては、LogEntry__c / Log__c レコードが生成される前に、追加で System.Test.getEventBus().deliver() を呼び出す必要があります。これが重要になるのは、次の 2 つのケースです。
Logger.setSaveMethod(Logger.SaveMethod.QUEUEABLE)またはLogger.saveLog(Logger.SaveMethod.QUEUEABLE)- Nebula Logger のキュー可能ベースの保存処理では、キュー可能の内部からプラットフォームイベントが公開されます。キュー可能はstopTest中に実行されますが、そこで公開されたイベントを配信するには、2 回目の配信処理が必要です。- テスト対象の非同期コード自体がログを記録する場合 -
Logger.info(...)/.error(...)/saveLog()をexecute内で呼び出すSystem.Queueable、System.Finalizer、またはDatabase.Batchableは、非同期コンテキスト内からプラットフォームイベントを公開します。stopTestは非同期ジョブを実行しますが、そのジョブが生成したプラットフォームイベントは配信しません。
@IsTest
static void it_should_log_the_error_from_a_failed_queueable() {
System.Test.startTest();
System.enqueueJob(new ExampleFailedQueueable());
System.Test.stopTest();
System.Test.getEventBus().deliver();
List<LogEntry__c> entries = [SELECT LoggingLevel__c FROM LogEntry__c WHERE LoggingLevel__c = 'ERROR'];
System.Assert.areEqual(1, entries.size());
}
デフォルトの EVENT_BUS 保存方法を使用する同期コードでは、stopTest だけで十分です。追加の deliver 呼び出しは必要ありません。
@IsTest
static void it_should_log_the_error_message_when_credit_check_throws() {
Account account = new Account(Name = 'Test Account');
insert account;
System.Test.startTest();
System.Exception thrownException;
try {
new CreditCheckService().evaluate(account.Id);
System.Assert.fail('Expected an exception');
} catch (System.Exception ex) {
thrownException = ex;
}
System.Test.stopTest();
System.Assert.areNotEqual('Expected an exception', thrownException.getMessage(), 'The wrong exception was thrown!');
List<LogEntry__c> entries = [
SELECT LoggingLevel__c, Message__c, RecordId__c, ExceptionMessage__c, ExceptionType__c
FROM LogEntry__c
];
System.Assert.areEqual(1, entries.size());
System.Assert.areEqual('ERROR', entries[0].LoggingLevel__c);
System.Assert.areEqual(thrownException.getMessage(), entries[0].ExceptionMessage__c);
System.Assert.areEqual(thrownException.getTypeName(), entries[0].ExceptionType__c);
}
エントリーが永続化されるかどうかを制御する
デフォルトでは、Nebula Logger はテストコンテキスト内で LoggerSettings__c を尊重します。組織のデフォルト設定で適切なレベルのロギングが有効になっている場合、エントリーは永続化されます。テスト対象のコードをデータベースに触れずに実行するには、次の方法があります。
- テストの先頭で
Logger.suspendSaving()を呼び出します。その後のsaveLog()呼び出しは何もしません。レコードは挿入されず、プラットフォームイベントも公開されず、バッファーにも手を加えません。 Logger.resumeSaving()を呼び出すと、一時停止が解除されます。保存が一時停止されている間にバッファーに蓄積されたエントリーはすべて残っているため、次のsaveLog()呼び出しですべてフラッシュされます。永続化せずに破棄する場合は、再開する前にLogger.flushBuffer()を呼び出します。- セットアップが完了する前に、テストで生成されたエントリーが蓄積されるのを防ぎたいだけの場合は、テストの先頭で
Logger.flushBuffer()を呼び出します。 - 共有テストユーティリティを作成する際にテストへの影響を防ぐには、
Logger.isSavingSuspended()を呼び出して状態を確認します。
@IsTest
static void it_should_not_persist_log_records_when_saving_is_suspended() {
Logger.suspendSaving();
new CreditCheckService().evaluate(fakeAccountId());
Logger.saveLog();
System.Assert.isTrue([SELECT COUNT() FROM Log__c] == 0);
}
Nebula Logger の CMDT レコードはテスト中も有効です
Salesforce では、テストが CMDT をクエリすると、組織の実際のカスタムメタデータレコードが返されます。プラットフォームは、sObject データのようにこれらをロールバックしません。Nebula Logger はこの仕組みを活用しています。内部セレクターレイヤーは、組織にデプロイされている LoggerParameter__mdt、LogEntryDataMaskRule__mdt、LogEntryTagRule__mdt、LoggerFieldMapping__mdt、LoggerPlugin__mdt、LoggerScenarioRule__mdt、LoggerSObjectHandler__mdt、LogStatus__mdt の各レコードを読み取り、実行時と同じようにテスト中にも使用します。
利用者独自のテストにおける実際上の影響は次のとおりです。
- 組織内の
LoggerParameter__mdt.Value__cを変更すると(たとえば、QueryUserDataSynchronouslyをtrueからfalseに切り替えたり、Boolean を想定するパラメーターに Boolean 以外の値を設定したりすると)、実行時だけでなくテストの動作にも影響します。標準設定を前提としていたテストは、設定変更後に失敗する場合があります。 - 新たにデプロイした
LogEntryDataMaskRule__mdtレコードは、テスト内でも機密データをマスクします。そのため、生のメッセージテキストに対するアサーションでは、マスク後の形式を想定する必要があります。 - 新たに追加した
LoggerPlugin__mdtレコードもテスト中に実行されます。プラグインに副作用(コールアウト、DML、プラットフォームイベント)がある場合、テストではそれらをモックするか、考慮する必要があります。 LoggerScenario__mdtレコードは、実行時と同様に、テスト時にもLoggerSettings__cを上書きします。
CMDT の変更は動作の変更として扱い、Nebula Logger の CMDT レコードをカスタマイズしてデプロイした後は、関連するテストスイートを再実行してください。Nebula Logger 内部の LoggerConfigurationSelector.useMocks() シームは global ではないため、利用者のテストでは使用できません。サポートされている方法は、組織の CMDT の状態をテストで考慮し、永続化処理を対象外にする必要がある場合に Logger.suspendSaving()/flushBuffer() を使用することです。
LWC テストに関する考慮事項
sfdx-lwc-jest を使用する LWC テストでは、c/logger モジュールをモックし、コンポーネントが適切なエントリーレベルを呼び出し、適切なメッセージ/レコードを渡すことをアサートします。
// __tests__/paymentPanel.test.js
import { createElement } from 'lwc';
import PaymentPanel from 'c/paymentPanel';
const mockLogger = {
setScenario: jest.fn(),
info: jest.fn().mockReturnThis(),
error: jest.fn().mockReturnThis(),
setExceptionDetails: jest.fn().mockReturnThis(),
saveLog: jest.fn()
};
jest.mock('c/logger', () => ({
getLogger: () => mockLogger
}));
describe('c-payment-panel', () => {
it('logs an INFO entry when the panel initializes', () => {
const element = createElement('c-payment-panel', { is: PaymentPanel });
document.body.appendChild(element);
expect(mockLogger.setScenario).toHaveBeenCalledWith('Payment UI');
expect(mockLogger.info).toHaveBeenCalledWith('Payment panel initialized');
expect(mockLogger.saveLog).toHaveBeenCalled();
});
});
リポジトリのテスト規約に従い、ロガーメソッドが呼び出されたことだけでなく、渡された引数をアサートしてください(toHaveBeenCalledWith(...))。toHaveBeenCalled() だけでは、メッセージテキストが失われたり文字化けしたりするリグレッションを見逃してしまいます。
テストコードで安全に使用できるグローバル API
独自のテストコードから使用できるのは、global API のみです。public はすべて Nebula Logger の内部インターフェースであり、予告なく変更される可能性があります。詳しくは、nebula-logger-instrumentation の「サポート対象の API インターフェース」セクションを参照してください。
以下はすべて global であり、いずれのパッケージでも、サブスクライバーのテストスイートから安全に呼び出せます。
Logger.getBufferSize()- バッファーに格納されているエントリー数を確認します。Logger.suspendSaving()/Logger.resumeSaving()/Logger.isSavingSuspended()- 永続化を防止または制御します。Logger.flushBuffer()- 永続化せずに、バッファー内のエントリーを破棄します。Logger.getTransactionId()- 永続化されたレコードを検証する際に、テストのログを関連付けます。Logger.setScenario(...)/Logger.endScenario(...)- 永続化されたログを簡単に識別できるよう、テスト固有のシナリオを設定します。- レベル固有のメソッド(
Logger.info(...)、Logger.error(...)など)とLogger.saveLog()。
関連スキル
- nebula-logger-instrumentation - テスト対象の API です。
- nebula-logger-best-practices - テスト対象のコードが従うべき規約です。