You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Jest模拟fs函数:新手如何测试Winston Logger类

Hey there! Since you're new to ES6 and Jest, let's walk through how to test your Winston Logger class properly. First, I'll assume a complete version of your Logger class (since your code snippet got cut off), then we'll build out the tests step by step.

First, Let's Finalize Your Logger Class

Here's a plausible complete version based on your snippet (fill in any gaps to match your actual code):

const winston = require('winston');
const fs = require('fs');
const path = require('path');
const config = require('../config.json');

class Logger {
  static logDir = path.join(__dirname, '../logs');

  constructor() {
    Logger.createLogDir(Logger.logDir);
    this.logger = winston.createLogger({
      level: config.logLevel || 'info',
      format: winston.format.json(),
      transports: [
        new winston.transports.Console({
          format: winston.format.combine(
            winston.format.colorize(),
            winston.format.simple()
          )
        }),
        new winston.transports.File({ filename: path.join(Logger.logDir, 'error.log'), level: 'error' }),
        new winston.transports.File({ filename: path.join(Logger.logDir, 'combined.log') })
      ]
    });
  }

  static createLogDir(dir) {
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir, { recursive: true });
    }
  }

  info(message) {
    this.logger.info(message);
  }

  error(message) {
    this.logger.error(message);
  }
}

module.exports = Logger;
Testing Your Winston Logger with Jest

The key here is to mock external dependencies (like fs and winston) so we don't create real files or directories during tests—this keeps tests fast and isolated.

1. Set Up Mocks

Create a test file (e.g., logger.test.js) and start by mocking the modules we don't want to run for real:

const Logger = require('./Logger');
const winston = require('winston');
const fs = require('fs');

// Mock the fs module to avoid real directory creation
jest.mock('fs');

// Mock winston to track calls to its logger methods
jest.mock('winston', () => {
  const mockLogger = {
    info: jest.fn(),
    error: jest.fn()
  };
  return {
    createLogger: jest.fn(() => mockLogger),
    transports: {
      Console: jest.fn(),
      File: jest.fn()
    },
    format: {
      json: jest.fn(),
      combine: jest.fn(),
      colorize: jest.fn(),
      simple: jest.fn()
    }
  };
});

2. Test Directory Creation Logic

We want to verify that createLogDir works as expected—creating the directory only when it doesn't exist:

describe('Logger', () => {
  // Reset all mock calls between tests to avoid cross-test contamination
  beforeEach(() => {
    jest.clearAllMocks();
  });

  test('creates log directory when it does not exist', () => {
    // Mock fs.existsSync to pretend the directory doesn't exist
    fs.existsSync.mockReturnValue(false);

    new Logger();

    expect(fs.existsSync).toHaveBeenCalledWith(Logger.logDir);
    expect(fs.mkdirSync).toHaveBeenCalledWith(Logger.logDir, { recursive: true });
  });

  test('does NOT create log directory when it already exists', () => {
    // Mock fs.existsSync to pretend the directory exists
    fs.existsSync.mockReturnValue(true);

    new Logger();

    expect(fs.existsSync).toHaveBeenCalledWith(Logger.logDir);
    expect(fs.mkdirSync).not.toHaveBeenCalled();
  });
});

3. Test Winston Logger Initialization

Verify that the constructor sets up the Winston logger with the correct configuration:

test('initializes Winston logger with correct config', () => {
  new Logger();

  expect(winston.createLogger).toHaveBeenCalled();
  // Check key config values (adjust to match your actual setup)
  const loggerConfig = winston.createLogger.mock.calls[0][0];
  expect(loggerConfig.level).toBe('info'); // or config.logLevel if you're using that
  expect(loggerConfig.transports).toHaveLength(3); // Match the number of transports in your class
});

4. Test Logging Methods

Make sure your info and error methods correctly delegate to the Winston logger:

test('calls Winston info method with the provided message', () => {
  const logger = new Logger();
  const testMsg = 'User logged in successfully';

  logger.info(testMsg);

  expect(winston.createLogger().info).toHaveBeenCalledWith(testMsg);
});

test('calls Winston error method with the provided message', () => {
  const logger = new Logger();
  const testMsg = 'Failed to connect to database';

  logger.error(testMsg);

  expect(winston.createLogger().error).toHaveBeenCalledWith(testMsg);
});

Quick Tips for Beginners

  • Always use jest.clearAllMocks() in beforeEach—this ensures mocks don't retain calls from previous tests.
  • If your logger uses values from config.json, mock that file too with jest.mock('../config.json', () => ({ logLevel: 'debug' })) to test different scenarios.
  • If you want to verify log formatting, you can spy on console.log (for console transport) or mock file streams, but mocking is generally preferred for speed.

内容的提问来源于stack exchange,提问作者Oyabi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:11:10