Zum Inhalt

Mocha Cheatsheet

Insgesamt - Einfach, flexibel, Spaß JavaScript Testing

Mocha ist ein funktionsreiches JavaScript Test-Framework auf Node.js und im Browser, das asynchrone Tests einfach und lustig macht. Mocha-Tests laufen seriell, ermöglichen eine flexible und genaue Berichterstattung, während ungezogene Ausnahmen zu den richtigen Testfällen zu kartieren. < p>

generieren

Inhaltsverzeichnis

  • [Installation](#installation
  • (#getting-started)
  • [Teststruktur](LINK_2__
  • (Hooks)(LINK_3_)
  • [Bestimmungen](LINK_4__
  • [Async Testing](LINK_5_
  • [Konfiguration](#configuration_
  • [Reporter](LINK_7__
  • (#browser-testing)
  • (Mocking)(LINK_9_)
  • [Erweiterte Funktionen](#advanced-features
  • Plugins
  • [CI/CD Integration](LINK_12__
  • Beste Praktiken
  • (Debugging)(LINK_14_)
  • Performance
  • (#troubleshooting_)

Installation

Einfache Installation

# Install Mocha globally
npm install -g mocha

# Install Mocha locally (recommended)
npm install --save-dev mocha

# Install with assertion library
npm install --save-dev mocha chai

# Install with additional tools
npm install --save-dev mocha chai sinon nyc
```_

### Projektaufbau
```bash
# Initialize new project
mkdir my-mocha-project
cd my-mocha-project
npm init -y

# Install dependencies
npm install --save-dev mocha chai

# Create test directory
mkdir test

# Create first test file
touch test/test.js
```_

### Paket.json Konfiguration
```json
{
  "scripts": {
    "test": "mocha",
    "test:watch": "mocha --watch",
    "test:coverage": "nyc mocha",
    "test:reporter": "mocha --reporter spec",
    "test:grep": "mocha --grep 'pattern'",
    "test:timeout": "mocha --timeout 5000"
  },
  "devDependencies": {
    "mocha": "^10.0.0",
    "chai": "^4.3.0",
    "sinon": "^15.0.0",
    "nyc": "^15.1.0"
  }
}
```_

### Verzeichnis Struktur
my-project/ ├── lib/ │ ├── calculator.js │ └── utils.js ├── test/ │ ├── calculator.test.js │ ├── utils.test.js │ └── helpers/ │ └── setup.js ├── .mocharc.json ├── package.json └── README.md
## Erste Schritte

### Erster Test
```javascript
// lib/calculator.js
function add(a, b) {
  return a + b;
}

function subtract(a, b) {
  return a - b;
}

function multiply(a, b) {
  return a * b;
}

function divide(a, b) {
  if (b === 0) {
    throw new Error('Division by zero');
  }
  return a / b;
}

module.exports = { add, subtract, multiply, divide };
```_

```javascript
// test/calculator.test.js
const { expect } = require('chai');
const { add, subtract, multiply, divide } = require('../lib/calculator');

describe('Calculator', function() {
  describe('Addition', function() {
    it('should add two positive numbers', function() {
      expect(add(2, 3)).to.equal(5);
    });

    it('should add negative numbers', function() {
      expect(add(-2, -3)).to.equal(-5);
    });

    it('should add zero', function() {
      expect(add(5, 0)).to.equal(5);
    });
  });

  describe('Division', function() {
    it('should divide positive numbers', function() {
      expect(divide(10, 2)).to.equal(5);
    });

    it('should throw error for division by zero', function() {
      expect(() => divide(10, 0)).to.throw('Division by zero');
    });
  });
});
```_

### Laufende Prüfungen
```bash
# Run all tests
npm test

# Run specific test file
npx mocha test/calculator.test.js

# Run tests with pattern
npx mocha test/**/*.test.js

# Run tests with grep
npx mocha --grep "Addition"

# Run tests in watch mode
npx mocha --watch

# Run tests with reporter
npx mocha --reporter json
```_

### Basistest Syntax
```javascript
// Test suite
describe('Feature Name', function() {
  // Test case
  it('should do something', function() {
    // Test implementation
  });

  // Pending test
  it('should do something else');

  // Skipped test
  it.skip('should skip this test', function() {
    // This won't run
  });

  // Only run this test
  it.only('should only run this test', function() {
    // Only this test will run
  });
});
```_

## Prüfstruktur

### Blocks abschreiben
```javascript
describe('User Management', function() {
  describe('User Creation', function() {
    it('should create a new user', function() {
      // Test implementation
    });

    it('should validate user data', function() {
      // Test implementation
    });
  });

  describe('User Authentication', function() {
    it('should authenticate valid user', function() {
      // Test implementation
    });

    it('should reject invalid credentials', function() {
      // Test implementation
    });
  });
});
```_

### Eingebettete Abschriften
```javascript
describe('API', function() {
  describe('Users Endpoint', function() {
    describe('GET /users', function() {
      it('should return all users', function() {
        // Test implementation
      });

      it('should return 200 status', function() {
        // Test implementation
      });
    });

    describe('POST /users', function() {
      it('should create new user', function() {
        // Test implementation
      });

      it('should return 201 status', function() {
        // Test implementation
      });
    });
  });
});
```_

### Prüforganisation
```javascript
// Good: Descriptive test names
describe('Email Validator', function() {
  it('should return true for valid email addresses', function() {
    // Test implementation
  });

  it('should return false for invalid email addresses', function() {
    // Test implementation
  });

  it('should handle edge cases like empty strings', function() {
    // Test implementation
  });
});

// Good: Group related functionality
describe('Shopping Cart', function() {
  describe('Adding Items', function() {
    it('should add item to cart');
    it('should update cart total');
    it('should increment item count');
  });

  describe('Removing Items', function() {
    it('should remove item from cart');
    it('should update cart total');
    it('should decrement item count');
  });
});
```_

### Testkontext
```javascript
describe('User Service', function() {
  context('when user exists', function() {
    it('should return user data', function() {
      // Test implementation
    });

    it('should update user successfully', function() {
      // Test implementation
    });
  });

  context('when user does not exist', function() {
    it('should return null', function() {
      // Test implementation
    });

    it('should throw error on update', function() {
      // Test implementation
    });
  });
});
```_

## Haken

### Grund Haken
```javascript
describe('Database Tests', function() {
  // Runs once before all tests in this describe block
  before(function() {
    console.log('Setting up database connection');
    // Setup code here
  });

  // Runs once after all tests in this describe block
  after(function() {
    console.log('Closing database connection');
    // Cleanup code here
  });

  // Runs before each test in this describe block
  beforeEach(function() {
    console.log('Preparing test data');
    // Setup for each test
  });

  // Runs after each test in this describe block
  afterEach(function() {
    console.log('Cleaning up test data');
    // Cleanup after each test
  });

  it('should save user', function() {
    // Test implementation
  });

  it('should find user', function() {
    // Test implementation
  });
});
```_

### Async Haken
```javascript
describe('Async Setup', function() {
  before(async function() {
    this.timeout(5000); // Increase timeout for setup

    // Async setup
    this.database = await connectToDatabase();
    this.server = await startServer();
  });

  after(async function() {
    // Async cleanup
    await this.database.close();
    await this.server.stop();
  });

  beforeEach(async function() {
    // Clear database before each test
    await this.database.clear();

    // Seed test data
    await this.database.seed({
      users: [
        { name: 'John', email: 'john@example.com' },
        { name: 'Jane', email: 'jane@example.com' }
      ]
    });
  });

  it('should find users', async function() {
    const users = await this.database.findAll('users');
    expect(users).to.have.length(2);
  });
});
```_

### Hook Erbteil
```javascript
describe('Parent Suite', function() {
  before(function() {
    console.log('Parent before');
  });

  beforeEach(function() {
    console.log('Parent beforeEach');
  });

  describe('Child Suite', function() {
    before(function() {
      console.log('Child before');
    });

    beforeEach(function() {
      console.log('Child beforeEach');
    });

    it('should inherit hooks', function() {
      // Execution order:
      // 1. Parent before
      // 2. Child before
      // 3. Parent beforeEach
      // 4. Child beforeEach
      // 5. Test execution
    });
  });
});
```_

### Bedingte Haken
```javascript
describe('Conditional Setup', function() {
  before(function() {
    if (process.env.NODE_ENV === 'test') {
      // Only run in test environment
      this.mockServer = startMockServer();
    }
  });

  beforeEach(function() {
    // Skip setup for specific tests
    if (this.currentTest.title.includes('integration')) {
      this.skip();
    }
  });

  it('should run unit test', function() {
    // This will run
  });

  it('should run integration test', function() {
    // This will be skipped by beforeEach
  });
});
```_

## Beschwörung

### Chai Asser
```javascript
const { expect } = require('chai');

describe('Chai Assertions', function() {
  it('should test equality', function() {
    expect(2 + 2).to.equal(4);
    expect({ name: 'John' }).to.deep.equal({ name: 'John' });
    expect([1, 2, 3]).to.deep.equal([1, 2, 3]);
  });

  it('should test truthiness', function() {
    expect(true).to.be.true;
    expect(false).to.be.false;
    expect(null).to.be.null;
    expect(undefined).to.be.undefined;
    expect('hello').to.exist;
  });

  it('should test types', function() {
    expect('hello').to.be.a('string');
    expect(42).to.be.a('number');
    expect([]).to.be.an('array');
    expect({}).to.be.an('object');
    expect(() => {}).to.be.a('function');
  });

  it('should test properties', function() {
    const obj = { name: 'John', age: 30 };
    expect(obj).to.have.property('name');
    expect(obj).to.have.property('age', 30);
    expect(obj).to.have.all.keys('name', 'age');
  });

  it('should test arrays', function() {
    const arr = [1, 2, 3, 4, 5];
    expect(arr).to.have.length(5);
    expect(arr).to.include(3);
    expect(arr).to.include.members([2, 4]);
    expect(arr).to.have.ordered.members([1, 2, 3, 4, 5]);
  });

  it('should test strings', function() {
    expect('hello world').to.contain('world');
    expect('hello world').to.match(/^hello/);
    expect('hello world').to.have.length(11);
  });
});
```_

### Zollanmeldungen
```javascript
const { expect } = require('chai');

// Extend Chai with custom assertion
chai.use(function(chai, utils) {
  chai.Assertion.addMethod('validEmail', function() {
    const obj = this._obj;
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

    this.assert(
      emailRegex.test(obj),
      'expected #{this} to be a valid email',
      'expected #{this} not to be a valid email'
    );
  });
});

describe('Custom Assertions', function() {
  it('should validate email addresses', function() {
    expect('user@example.com').to.be.validEmail;
    expect('invalid-email').to.not.be.validEmail;
  });
});
```_

### Sollten Style Asser
```javascript
const should = require('chai').should();

describe('Should Style', function() {
  it('should use should syntax', function() {
    const user = { name: 'John', age: 30 };

    user.should.be.an('object');
    user.should.have.property('name', 'John');
    user.age.should.equal(30);

    const numbers = [1, 2, 3];
    numbers.should.have.length(3);
    numbers.should.include(2);
  });
});
```_

### Assert Style Asserierung
```javascript
const assert = require('chai').assert;

describe('Assert Style', function() {
  it('should use assert syntax', function() {
    const user = { name: 'John', age: 30 };

    assert.isObject(user);
    assert.property(user, 'name');
    assert.equal(user.name, 'John');
    assert.equal(user.age, 30);

    const numbers = [1, 2, 3];
    assert.lengthOf(numbers, 3);
    assert.include(numbers, 2);
  });
});
```_

## Async Testing

### Verfahren
```javascript
describe('Promise Testing', function() {
  it('should resolve promise', function() {
    return fetchUser(1).then(user => {
      expect(user.name).to.equal('John');
    });
  });

  it('should reject promise', function() {
    return fetchUser(-1).catch(error => {
      expect(error.message).to.equal('User not found');
    });
  });

  it('should use async/await', async function() {
    const user = await fetchUser(1);
    expect(user.name).to.equal('John');
  });

  it('should handle async errors', async function() {
    try {
      await fetchUser(-1);
      throw new Error('Should have thrown');
    } catch (error) {
      expect(error.message).to.equal('User not found');
    }
  });
});
```_

### Rückrufe
```javascript
describe('Callback Testing', function() {
  it('should handle callbacks with done', function(done) {
    fetchUserCallback(1, (error, user) => {
      if (error) return done(error);

      try {
        expect(user.name).to.equal('John');
        done();
      } catch (assertionError) {
        done(assertionError);
      }
    });
  });

  it('should handle callback errors', function(done) {
    fetchUserCallback(-1, (error, user) => {
      try {
        expect(error).to.exist;
        expect(error.message).to.equal('User not found');
        expect(user).to.not.exist;
        done();
      } catch (assertionError) {
        done(assertionError);
      }
    });
  });
});
```_

### Timeouts
```javascript
describe('Timeout Testing', function() {
  // Set timeout for entire suite
  this.timeout(5000);

  it('should complete within timeout', function(done) {
    // Set timeout for specific test
    this.timeout(2000);

    setTimeout(() => {
      expect(true).to.be.true;
      done();
    }, 1000);
  });

  it('should handle slow operations', async function() {
    this.timeout(10000);

    const result = await slowOperation();
    expect(result).to.exist;
  });

  it('should disable timeout', function(done) {
    this.timeout(0); // Disable timeout

    // Very slow operation
    setTimeout(done, 30000);
  });
});
```_

### Retouren
```javascript
describe('Retry Testing', function() {
  // Retry failed tests
  this.retries(3);

  it('should retry flaky test', function() {
    // This test might fail randomly
    if (Math.random() < 0.7) {
      throw new Error('Random failure');
    }
    expect(true).to.be.true;
  });

  it('should retry specific test', function() {
    this.retries(5);

    // Test implementation
  });
});
```_

## Konfiguration

### Mocha Konfigurationsdatei
```json
// .mocharc.json
{
  "spec": "test/**/*.test.js",
  "require": ["test/helpers/setup.js"],
  "timeout": 5000,
  "reporter": "spec",
  "recursive": true,
  "exit": true,
  "bail": false,
  "grep": "",
  "invert": false,
  "checkLeaks": true,
  "globals": ["expect", "sinon"],
  "retries": 0,
  "slow": 75,
  "ui": "bdd"
}
```_

### JavaScript Konfiguration
```javascript
// .mocharc.js
module.exports = {
  spec: 'test/**/*.test.js',
  require: ['test/helpers/setup.js'],
  timeout: 5000,
  reporter: 'spec',
  recursive: true,
  exit: true,

  // Environment-specific configuration
  ...(process.env.NODE_ENV === 'ci' && {
    reporter: 'json',
    timeout: 10000,
    retries: 2
  })
};
```_

### Datei einrichten
```javascript
// test/helpers/setup.js
const chai = require('chai');
const sinon = require('sinon');

// Global setup
global.expect = chai.expect;
global.sinon = sinon;

// Chai plugins
chai.use(require('chai-as-promised'));
chai.use(require('sinon-chai'));

// Global hooks
before(function() {
  console.log('Global setup');
});

after(function() {
  console.log('Global cleanup');
});

beforeEach(function() {
  // Reset sinon stubs/spies
  sinon.restore();
});
```_

### Umweltvariablen
```javascript
// test/helpers/setup.js
process.env.NODE_ENV = 'test';
process.env.DATABASE_URL = 'mongodb://localhost:27017/test';
process.env.API_URL = 'http://localhost:3001';

// Load environment-specific config
if (process.env.CI) {
  // CI-specific setup
  process.env.TIMEOUT = '10000';
} else {
  // Local development setup
  process.env.TIMEOUT = '5000';
}
```_

### Mehrere Konfigurationen
```javascript
// mocha.config.js
const baseConfig = {
  timeout: 5000,
  recursive: true,
  exit: true
};

const configs = {
  unit: {
    ...baseConfig,
    spec: 'test/unit/**/*.test.js',
    reporter: 'spec'
  },

  integration: {
    ...baseConfig,
    spec: 'test/integration/**/*.test.js',
    timeout: 10000,
    reporter: 'json'
  },

  e2e: {
    ...baseConfig,
    spec: 'test/e2e/**/*.test.js',
    timeout: 30000,
    reporter: 'tap'
  }
};

module.exports = configs[process.env.TEST_TYPE] || configs.unit;
```_

## Berichterstattung

### Eingebaute Reporter
```bash
# Spec reporter (default)
npx mocha --reporter spec

# JSON reporter
npx mocha --reporter json

# TAP reporter
npx mocha --reporter tap

# Dot reporter
npx mocha --reporter dot

# Progress reporter
npx mocha --reporter progress

# Min reporter
npx mocha --reporter min

# Landing reporter
npx mocha --reporter landing

# List reporter
npx mocha --reporter list
```_

### Zollberichterstatter
```javascript
// reporters/custom-reporter.js
function CustomReporter(runner) {
  const stats = runner.stats;

  runner.on('start', function() {
    console.log('🚀 Starting test run...');
  });

  runner.on('suite', function(suite) {
    if (suite.root) return;
    console.log(`📁 ${suite.title}`);
  });

  runner.on('test', function(test) {
    console.log(`  ▶️  ${test.title}`);
  });

  runner.on('pass', function(test) {
    console.log(`  ✅ ${test.title} (${test.duration}ms)`);
  });

  runner.on('fail', function(test, err) {
    console.log(`  ❌ ${test.title}`);
    console.log(`     ${err.message}`);
  });

  runner.on('end', function() {
    console.log(`🏁 ${stats.passes} passed, ${stats.failures} failed`);
  });
}

module.exports = CustomReporter;

// Usage
// npx mocha --reporter ./reporters/custom-reporter.js
```_

### Reporter mit Dateiausgang
```javascript
// reporters/file-reporter.js
const fs = require('fs');
const path = require('path');

function FileReporter(runner, options) {
  const reportPath = options.reporterOptions?.output || 'test-results.json';
  const results = {
    stats: {},
    tests: [],
    failures: []
  };

  runner.on('start', function() {
    results.stats.start = new Date();
  });

  runner.on('pass', function(test) {
    results.tests.push({
      title: test.title,
      fullTitle: test.fullTitle(),
      duration: test.duration,
      state: 'passed'
    });
  });

  runner.on('fail', function(test, err) {
    results.tests.push({
      title: test.title,
      fullTitle: test.fullTitle(),
      duration: test.duration,
      state: 'failed',
      error: err.message
    });

    results.failures.push({
      title: test.fullTitle(),
      error: err.message,
      stack: err.stack
    });
  });

  runner.on('end', function() {
    results.stats.end = new Date();
    results.stats.duration = results.stats.end - results.stats.start;
    results.stats.passes = runner.stats.passes;
    results.stats.failures = runner.stats.failures;

    fs.writeFileSync(reportPath, JSON.stringify(results, null, 2));
    console.log(`Report written to ${reportPath}`);
  });
}

module.exports = FileReporter;
```_

### Mehrere Reporter
```bash
# Install multi-reporter
npm install --save-dev mocha-multi-reporters

# Configuration file
# multi-reporter-config.json
{
  "reporterEnabled": "spec,json,tap",
  "jsonReporterOptions": {
    "output": "test-results.json"
  },
  "tapReporterOptions": {
    "output": "test-results.tap"
  }
}

# Run with multiple reporters
npx mocha --reporter mocha-multi-reporters --reporter-options configFile=multi-reporter-config.json
```_

## Browser-Testing

### Browser-Setup
```html
<!-- test/browser/index.html -->
<!DOCTYPE html>
<html>
<head>
  <title>Mocha Browser Tests</title>
  <link rel="stylesheet" href="https://unpkg.com/mocha/mocha.css">
</head>
<body>
  <div id="mocha"></div>

  <!-- Mocha -->
  <script src="https://unpkg.com/mocha/mocha.js"></script>

  <!-- Chai -->
  <script src="https://unpkg.com/chai/chai.js"></script>

  <!-- Setup -->
  <script>
    mocha.setup('bdd');
    const expect = chai.expect;
  </script>

  <!-- Your code -->
  <script src="../lib/calculator.js"></script>

  <!-- Your tests -->
  <script src="calculator.test.js"></script>

  <!-- Run tests -->
  <script>
    mocha.run();
  </script>
</body>
</html>
```_

### Browser Testdatei
```javascript
// test/browser/calculator.test.js
describe('Calculator (Browser)', function() {
  it('should add numbers', function() {
    expect(add(2, 3)).to.equal(5);
  });

  it('should work with DOM', function() {
    const div = document.createElement('div');
    div.textContent = 'Hello World';
    document.body.appendChild(div);

    expect(div.textContent).to.equal('Hello World');

    document.body.removeChild(div);
  });

  it('should test localStorage', function() {
    localStorage.setItem('test', 'value');
    expect(localStorage.getItem('test')).to.equal('value');
    localStorage.removeItem('test');
  });
});
```_

### Webpack Integration
```javascript
// webpack.config.js
const path = require('path');

module.exports = {
  mode: 'development',
  entry: './test/browser/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'test-bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
  }
};
```_

### Plüsch-Integration
```javascript
// test/browser/puppeteer.test.js
const puppeteer = require('puppeteer');
const { expect } = require('chai');

describe('Browser Tests with Puppeteer', function() {
  let browser, page;

  before(async function() {
    browser = await puppeteer.launch();
    page = await browser.newPage();
  });

  after(async function() {
    await browser.close();
  });

  it('should run tests in browser', async function() {
    await page.goto('file://' + __dirname + '/index.html');

    // Wait for tests to complete
    await page.waitForFunction(() => {
      return window.mochaResults && window.mochaResults.complete;
    });

    const results = await page.evaluate(() => window.mochaResults);
    expect(results.failures).to.equal(0);
  });
});
```_

## Mocking

### Integration von Sinon
```javascript
const sinon = require('sinon');
const { expect } = require('chai');

describe('Mocking with Sinon', function() {
  afterEach(function() {
    sinon.restore();
  });

  it('should mock functions', function() {
    const callback = sinon.fake();
    const proxy = sinon.fake.returns(42);

    callback('hello', 'world');
    expect(callback.calledWith('hello', 'world')).to.be.true;

    expect(proxy()).to.equal(42);
  });

  it('should stub methods', function() {
    const user = {
      getName: () => 'John',
      setName: (name) => { this.name = name; }
    };

    const stub = sinon.stub(user, 'getName').returns('Jane');

    expect(user.getName()).to.equal('Jane');
    expect(stub.calledOnce).to.be.true;
  });

  it('should spy on methods', function() {
    const user = {
      getName: () => 'John'
    };

    const spy = sinon.spy(user, 'getName');

    user.getName();
    user.getName();

    expect(spy.calledTwice).to.be.true;
  });
});
```_

### HTTP Mocking
```javascript
const nock = require('nock');
const axios = require('axios');
const { expect } = require('chai');

describe('HTTP Mocking', function() {
  afterEach(function() {
    nock.cleanAll();
  });

  it('should mock HTTP requests', async function() {
    nock('https://api.example.com')
      .get('/users/1')
      .reply(200, { id: 1, name: 'John' });

    const response = await axios.get('https://api.example.com/users/1');
    expect(response.data.name).to.equal('John');
  });

  it('should mock POST requests', async function() {
    nock('https://api.example.com')
      .post('/users', { name: 'Jane' })
      .reply(201, { id: 2, name: 'Jane' });

    const response = await axios.post('https://api.example.com/users', {
      name: 'Jane'
    });

    expect(response.status).to.equal(201);
    expect(response.data.id).to.equal(2);
  });

  it('should mock with delays', async function() {
    nock('https://api.example.com')
      .get('/slow')
      .delay(1000)
      .reply(200, { message: 'slow response' });

    const start = Date.now();
    await axios.get('https://api.example.com/slow');
    const duration = Date.now() - start;

    expect(duration).to.be.at.least(1000);
  });
});
```_

### Modul Mocking
```javascript
const proxyquire = require('proxyquire');
const { expect } = require('chai');

describe('Module Mocking', function() {
  it('should mock required modules', function() {
    const dbMock = {
      findUser: sinon.stub().returns({ id: 1, name: 'John' })
    };

    const UserService = proxyquire('../lib/user-service', {
      './database': dbMock
    });

    const user = UserService.getUser(1);
    expect(user.name).to.equal('John');
    expect(dbMock.findUser.calledWith(1)).to.be.true;
  });

  it('should mock with multiple dependencies', function() {
    const mocks = {
      './database': {
        connect: sinon.stub(),
        query: sinon.stub().returns([])
      },
      './logger': {
        log: sinon.stub(),
        error: sinon.stub()
      }
    };

    const Service = proxyquire('../lib/service', mocks);

    Service.initialize();
    expect(mocks['./database'].connect.called).to.be.true;
    expect(mocks['./logger'].log.called).to.be.true;
  });
});
```_

## Erweiterte Funktionen

### Parallele Prüfung
```bash
# Install parallel testing
npm install --save-dev mocha-parallel-tests

# Run tests in parallel
npx mocha-parallel-tests

# Specify max parallel processes
npx mocha-parallel-tests --max-parallel 4
```_

### Prüffilter
```bash
# Run tests matching pattern
npx mocha --grep "should add"

# Run tests NOT matching pattern
npx mocha --grep "should add" --invert

# Run tests in specific files
npx mocha test/unit/**/*.test.js

# Run tests with tags
npx mocha --grep "@slow"
```_

```javascript
// Tag tests with comments
describe('Calculator', function() {
  it('should add quickly @fast', function() {
    // Fast test
  });

  it('should handle complex calculations @slow', function() {
    // Slow test
  });
});
```_

### Dynamische Testgeneration
```javascript
describe('Dynamic Tests', function() {
  const testCases = [
    { input: [2, 3], expected: 5 },
    { input: [5, 7], expected: 12 },
    { input: [-1, 1], expected: 0 },
    { input: [0, 0], expected: 0 }
  ];

  testCases.forEach(({ input, expected }) => {
    it(`should add ${input[0]} + ${input[1]} = ${expected}`, function() {
      expect(add(input[0], input[1])).to.equal(expected);
    });
  });
});

// Async dynamic tests
describe('API Endpoints', function() {
  let endpoints;

  before(async function() {
    endpoints = await loadEndpointsConfig();
  });

  function createEndpointTest(endpoint) {
    it(`should respond to ${endpoint.method} ${endpoint.path}`, async function() {
      const response = await request(app)
        [endpoint.method.toLowerCase()](endpoint.path);

      expect(response.status).to.equal(endpoint.expectedStatus);
    });
  }

  // Generate tests after loading config
  before(function() {
    endpoints.forEach(createEndpointTest);
  });
});
```_

### Test Utilities
```javascript
// test/helpers/utils.js
const { expect } = require('chai');

function expectAsync(promise) {
  return {
    toResolve: async () => {
      try {
        const result = await promise;
        return result;
      } catch (error) {
        throw new Error(`Expected promise to resolve, but it rejected with: ${error.message}`);
      }
    },

    toReject: async (expectedError) => {
      try {
        await promise;
        throw new Error('Expected promise to reject, but it resolved');
      } catch (error) {
        if (expectedError) {
          expect(error.message).to.include(expectedError);
        }
        return error;
      }
    }
  };
}

function createUser(overrides = {}) {
  return {
    id: Math.floor(Math.random() * 1000),
    name: 'Test User',
    email: 'test@example.com',
    ...overrides
  };
}

module.exports = { expectAsync, createUser };
```_

### Testdatenfaktoren
```javascript
// test/factories/user-factory.js
class UserFactory {
  static create(overrides = {}) {
    return {
      id: this.generateId(),
      name: 'John Doe',
      email: 'john@example.com',
      age: 30,
      active: true,
      createdAt: new Date(),
      ...overrides
    };
  }

  static createMany(count, overrides = {}) {
    return Array.from({ length: count }, (_, index) => 
      this.create({ id: index + 1, ...overrides })
    );
  }

  static generateId() {
    return Math.floor(Math.random() * 10000);
  }
}

module.exports = UserFactory;

// Usage in tests
const UserFactory = require('./factories/user-factory');

describe('User Service', function() {
  it('should process user', function() {
    const user = UserFactory.create({ name: 'Jane' });
    const result = processUser(user);
    expect(result.displayName).to.equal('Jane');
  });

  it('should handle multiple users', function() {
    const users = UserFactory.createMany(5);
    expect(users).to.have.length(5);
  });
});
```_

## Plugins

### Beliebte Plugins
```bash
# Chai plugins
npm install --save-dev chai-as-promised chai-http chai-string

# Sinon integration
npm install --save-dev sinon-chai

# Coverage
npm install --save-dev nyc

# Parallel testing
npm install --save-dev mocha-parallel-tests

# Multi-reporters
npm install --save-dev mocha-multi-reporters
```_

### Chai Plugins Nutzung
```javascript
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
const chaiHttp = require('chai-http');
const chaiString = require('chai-string');

chai.use(chaiAsPromised);
chai.use(chaiHttp);
chai.use(chaiString);

const { expect } = chai;

describe('Chai Plugins', function() {
  it('should test promises', async function() {
    await expect(Promise.resolve('success')).to.eventually.equal('success');
    await expect(Promise.reject(new Error('fail'))).to.be.rejected;
  });

  it('should test HTTP', function() {
    return chai.request(app)
      .get('/api/users')
      .then(res => {
        expect(res).to.have.status(200);
        expect(res).to.be.json;
        expect(res.body).to.be.an('array');
      });
  });

  it('should test strings', function() {
    expect('Hello World').to.startWith('Hello');
    expect('Hello World').to.endWith('World');
    expect('Hello World').to.equalIgnoreCase('hello world');
  });
});
```_

### Benutzerdefinierte Plugin Entwicklung
```javascript
// chai-custom-plugin.js
module.exports = function(chai, utils) {
  chai.Assertion.addMethod('validEmail', function() {
    const obj = this._obj;
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

    this.assert(
      emailRegex.test(obj),
      'expected #{this} to be a valid email',
      'expected #{this} not to be a valid email'
    );
  });

  chai.Assertion.addMethod('between', function(min, max) {
    const obj = this._obj;

    this.assert(
      obj >= min && obj <= max,
      'expected #{this} to be between #{exp1} and #{exp2}',
      'expected #{this} not to be between #{exp1} and #{exp2}',
      `${min} and ${max}`
    );
  });
};

// Usage
const chai = require('chai');
chai.use(require('./chai-custom-plugin'));

describe('Custom Plugin', function() {
  it('should validate emails', function() {
    expect('user@example.com').to.be.validEmail;
  });

  it('should check ranges', function() {
    expect(5).to.be.between(1, 10);
  });
});
```_

## CI/CD Integration

### GitHub Aktionen
```yaml
# .github/workflows/test.yml
name: Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [16, 18, 20]

    steps:
    - uses: actions/checkout@v3

    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v3
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'npm'

    - name: Install dependencies
      run: npm ci

    - name: Run tests
      run: npm test

    - name: Run coverage
      run: npm run test:coverage

    - name: Upload coverage to Codecov
      uses: codecov/codecov-action@v3
      with:
        file: ./coverage/lcov.info
```_

### Jenkins Pipeline
```groovy
// Jenkinsfile
pipeline {
    agent any

    tools {
        nodejs '18'
    }

    stages {
        stage('Install') {
            steps {
                sh 'npm ci'
            }
        }

        stage('Test') {
            steps {
                sh 'npm test'
            }
            post {
                always {
                    publishTestResults testResultsPattern: 'test-results.xml'
                }
            }
        }

        stage('Coverage') {
            steps {
                sh 'npm run test:coverage'
            }
            post {
                always {
                    publishHTML([
                        allowMissing: false,
                        alwaysLinkToLastBuild: true,
                        keepAll: true,
                        reportDir: 'coverage',
                        reportFiles: 'index.html',
                        reportName: 'Coverage Report'
                    ])
                }
            }
        }
    }
}
```_

### Docker Integration
```dockerfile
# Dockerfile.test
FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci

COPY . .

CMD ["npm", "test"]
```_

```yaml
# docker-compose.test.yml
version: '3.8'
services:
  test:
    build:
      context: .
      dockerfile: Dockerfile.test
    environment:
      - NODE_ENV=test
    volumes:
      - ./coverage:/app/coverage
```_

## Best Practices

### Prüforganisation
```javascript
// Good: Clear test structure
describe('UserService', function() {
  describe('#createUser', function() {
    context('with valid data', function() {
      it('should create user successfully', function() {
        // Test implementation
      });

      it('should return user with ID', function() {
        // Test implementation
      });
    });

    context('with invalid data', function() {
      it('should throw validation error', function() {
        // Test implementation
      });
    });
  });
});

// Good: Descriptive test names
it('should return 404 when user does not exist', function() {
  // Test implementation
});

it('should update user email when valid email provided', function() {
  // Test implementation
});
```_

### Test Data Management
```javascript
// Good: Use factories for test data
const UserFactory = require('./factories/user-factory');

describe('User Tests', function() {
  it('should validate user', function() {
    const user = UserFactory.create({ email: 'invalid-email' });
    expect(() => validateUser(user)).to.throw();
  });
});

// Good: Clean up after tests
describe('Database Tests', function() {
  afterEach(async function() {
    await cleanupDatabase();
  });
});
```_

### Async Best Practices
```javascript
// Good: Proper async handling
describe('Async Tests', function() {
  it('should handle promises', async function() {
    const result = await asyncOperation();
    expect(result).to.exist;
  });

  it('should handle errors', async function() {
    await expect(failingOperation()).to.be.rejected;
  });
});

// Good: Proper timeout handling
describe('Slow Tests', function() {
  this.timeout(10000);

  it('should complete slow operation', async function() {
    const result = await slowOperation();
    expect(result).to.exist;
  });
});
```_

## Debugging

### Debug Mode
```bash
# Run with debug output
DEBUG=mocha* npm test

# Run specific test with debug
npx mocha --grep "specific test" --inspect-brk

# Debug with VS Code
# Add to launch.json
{
  "type": "node",
  "request": "launch",
  "name": "Mocha Debug",
  "program": "${workspaceFolder}/node_modules/.bin/mocha",
  "args": ["--timeout", "999999", "--colors", "${workspaceFolder}/test"],
  "console": "integratedTerminal",
  "internalConsoleOptions": "neverOpen"
}
```_

### Test Debugging
```javascript
describe('Debug Tests', function() {
  it('should debug test', function() {
    const data = { name: 'John', age: 30 };

    console.log('Debug data:', data);
    debugger; // Breakpoint for debugging

    expect(data.name).to.equal('John');
  });

  it('should log test progress', function() {
    console.log('Step 1: Setup');
    const user = createUser();

    console.log('Step 2: Process');
    const result = processUser(user);

    console.log('Step 3: Verify');
    expect(result).to.exist;
  });
});
```_

### Fehler Debugging
```javascript
describe('Error Debugging', function() {
  it('should provide detailed error info', function() {
    try {
      const result = complexOperation();
      expect(result.value).to.equal(42);
    } catch (error) {
      console.error('Test failed with error:', error);
      console.error('Stack trace:', error.stack);
      throw error;
    }
  });
});
```_

## Leistung

### Prüfleistung
```javascript
// Optimize test setup
describe('Performance Tests', function() {
  // Use before/after for expensive setup
  before(async function() {
    this.database = await setupDatabase();
  });

  after(async function() {
    await this.database.close();
  });

  // Avoid unnecessary work in tests
  it('should be fast', function() {
    // Minimal test implementation
    expect(true).to.be.true;
  });
});

Parallele Ausführung

```bash

Run tests in parallel

npx mocha-parallel-tests

Specify parallel workers

npx mocha-parallel-tests --max-parallel 4 ```_

Speicheroptimierung

```javascript // .mocharc.js module.exports = { // Optimize for memory usage timeout: 5000, bail: true, // Stop on first failure exit: true, // Force exit after tests

// Cleanup after tests require: ['test/helpers/cleanup.js'] }; ```_

Fehlerbehebung

Gemeinsame Themen

```javascript // Issue: Tests not running // Solution: Check file patterns and paths // .mocharc.json { "spec": "test/**/*.test.js", // Correct pattern "recursive": true }

// Issue: Async tests timing out // Solution: Increase timeout or fix async handling describe('Async Tests', function() { this.timeout(10000); // Increase timeout

it('should handle async', async function() { const result = await asyncOperation(); expect(result).to.exist; }); });

// Issue: Memory leaks // Solution: Proper cleanup afterEach(function() { // Clean up resources sinon.restore(); nock.cleanAll(); }); ```_

Debug Konfiguration

```javascript // Debug configuration issues console.log('Mocha config:', JSON.stringify(require('./.mocharc.json'), null, 2));

// Debug test discovery npx mocha --dry-run

// Debug reporter issues npx mocha --reporter json > test-results.json ```_

--

Zusammenfassung

Mocha ist ein flexibles und leistungsstarkes JavaScript-Test-Framework, das bietet:

  • **Flexible Structure*: Unterstützung für BDD, TDD und benutzerdefinierte Schnittstellen
  • **Async Support*: Native Unterstützung für Versprechungen, Callbacks und Async/await
  • **Rich Ecosystem*: Umfangreiches Plugin-Ökosystem und Integrationen
  • **Multiple Environments*: Runs in Node.js und Browser
  • ** Umfassende Reporting**: Mehrere eingebaute Reporter und benutzerdefinierte Reporter-Unterstützung
  • ** Fortgeschrittene Funktionen*: Parallele Tests, Testfilter und dynamische Testgeneration
  • **CI/CD Ready*: Ausgezeichnete Integration mit kontinuierlichen Integrationssystemen
  • **Debugging Support*: Reiche Debugging-Funktionen und Fehlerberichterstattung

Mocha zeichnet sich durch eine solide Grundlage für JavaScript-Tests mit seiner Flexibilität, umfangreichem Feature-Set und reifem Ökosystem aus. Sein unopinionierter Ansatz ermöglicht es Teams, Test-Workflows zu erstellen, die ihren spezifischen Bedürfnissen entsprechen und gleichzeitig exzellente Entwicklererfahrung und zuverlässige Testausführung beibehalten.

<= <= <= <================================================================================= Funktion copyToClipboard() {\cHFFFF} const commands = document.querySelectorAll('code'); alle Befehle = ''; Befehle. Für jede(cmd) => alle Befehle += cmd.textContent + '\n'); navigator.clipboard.writeText (allCommands); Alarm ('Alle Befehle, die in die Zwischenablage kopiert werden!'); }

Funktion generierenPDF() { Fenster.print(); }