From aec7c90eb6e17a606b95ef13a657946daa9c0d89 Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Mon, 12 Feb 2024 14:23:45 -0800 Subject: [PATCH] feat(fxtest): Add WithTestLogger option fxtest.New has this really nice behavior where by default, it uses the `testing.TB` as the destination for log output. Unfortunately, fxtest is not good for testing failure cases because it fails the test if the container failed. app := fxtest.New(t, fx.Invoke(func() error { return errors.New("fail") }), ) err := app.Start(ctx) // We never get here because fxtest.New has already failed the test. So the expectation there is to use `fx.New(..)` which, by default, logs to stderr. This can be addressed by using the `fx.WithLogger` option in combination with `fxtest.NewTestLogger`, but it ends up being a mouthful: app := fx.New( fx.Invoke(func() error { return errors.New("fail") }), fx.WithLogger(func() fxevent.Logger { return fxtest.NewTestLogger(t) }), ) This PR is a proposal and implementation of a new `fxtest.WithTestLogger` option that shortens the above to: app := fx.New( fx.Invoke(func() error { return errors.New("fail") }), fxtest.WithTestLogger(t), ) As an example, a couple tests in Fx itself become more readable with this new API. --- CHANGELOG.md | 6 ++++-- app_test.go | 4 ++-- fxtest/app.go | 3 +-- fxtest/printer.go | 8 ++++++++ 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b30c21c45..a571d75ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,8 +10,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unrelease -- No changes yet. +## Unreleased +### Added +- fxtest: Add WithTestLogger option that uses a `testing.TB` as the + Fx event logger. ## [1.20.1](https://github.com/uber-go/fx/compare/v1.20.0...v1.20.1) - 2023-10-17 diff --git a/app_test.go b/app_test.go index c9b9000b0..cc8fc426a 100644 --- a/app_test.go +++ b/app_test.go @@ -53,7 +53,7 @@ func NewForTest(tb testing.TB, opts ...Option) *App { // Provide both: Logger and WithLogger so that if the test // WithLogger fails, we don't pollute stderr. Logger(fxtest.NewTestPrinter(tb)), - WithLogger(func() fxevent.Logger { return fxtest.NewTestLogger(tb) }), + fxtest.WithTestLogger(tb), } opts = append(testOpts, opts...) @@ -73,7 +73,7 @@ func validateTestApp(tb testing.TB, opts ...Option) error { // Provide both: Logger and WithLogger so that if the test // WithLogger fails, we don't pollute stderr. Logger(fxtest.NewTestPrinter(tb)), - WithLogger(func() fxevent.Logger { return fxtest.NewTestLogger(tb) }), + fxtest.WithTestLogger(tb), } opts = append(testOpts, opts...) diff --git a/fxtest/app.go b/fxtest/app.go index 9ce2e8b1f..427f95422 100644 --- a/fxtest/app.go +++ b/fxtest/app.go @@ -24,7 +24,6 @@ import ( "context" "go.uber.org/fx" - "go.uber.org/fx/fxevent" ) // App is a wrapper around fx.App that provides some testing helpers. By @@ -38,7 +37,7 @@ type App struct { // New creates a new test application. func New(tb TB, opts ...fx.Option) *App { allOpts := make([]fx.Option, 0, len(opts)+1) - allOpts = append(allOpts, fx.WithLogger(func() fxevent.Logger { return NewTestLogger(tb) })) + allOpts = append(allOpts, WithTestLogger(tb)) allOpts = append(allOpts, opts...) app := fx.New(allOpts...) diff --git a/fxtest/printer.go b/fxtest/printer.go index 73f0f8f74..c16c155b6 100644 --- a/fxtest/printer.go +++ b/fxtest/printer.go @@ -32,6 +32,14 @@ func NewTestLogger(t TB) fxevent.Logger { return fxlog.DefaultLogger(testutil.WriteSyncer{T: t}) } +// WithTestLogger returns an fx.Option that uses the provided TB +// as the destination for Fx's log output. +func WithTestLogger(t TB) fx.Option { + return fx.WithLogger(func() fxevent.Logger { + return NewTestLogger(t) + }) +} + type testPrinter struct { TB }