スキル一覧に戻る
Luscii

test-assertions

by Luscii

Re-usable configuration of Parsers and Filter for Fluentbit

0🍴 0📅 2026年1月22日
GitHubで見るManusで実行

SKILL.md


name: test-assertions description: 'Write effective test assertions with clear error messages, null safety, and proper validation. Use when asked to "write assertions", "validate test results", "check conditions", "test expectations", or when writing any type of automated test. Applicable to Terraform, JavaScript, Python, Go, and other testing frameworks.'

Test Assertions

Write clear, effective test assertions that validate behavior and provide helpful feedback when tests fail.

When to Use This Skill

  • User asks to "write assertions", "add test validation", "check conditions"
  • Writing unit, integration, or end-to-end tests
  • Validating test outcomes and expectations
  • Testing error conditions and edge cases
  • Ensuring test failures are easy to debug
  • Writing negative tests (expect failures)

Assertion Fundamentals

Basic Structure

Pattern:

assert <condition> with <helpful error message>

Terraform:

assert {
  condition     = aws_s3_bucket.bucket.bucket == "expected-name"
  error_message = "S3 bucket name did not match expected value"
}

JavaScript (Jest):

expect(bucket.name).toBe('expected-name'); // Error: Expected: expected-name, Received: actual-name

Python (pytest):

assert bucket.name == 'expected-name', "S3 bucket name did not match expected value"

Go:

assert.Equal(t, "expected-name", bucket.Name, "S3 bucket name did not match expected value")

Error Message Best Practices

1. Include Actual Values

❌ Bad - No context:

assert {
  condition     = length(local.parsers) == 5
  error_message = "Wrong number of parsers"
}

✅ Good - Shows actual value:

assert {
  condition     = length(local.parsers) == 5
  error_message = "Expected 5 parsers, got ${length(local.parsers)}"
}

JavaScript:

// ✅ Jest automatically shows both values
expect(parsers.length).toBe(5);
// Output: Expected: 5, Received: 3

Python:

# ❌ Bad
assert len(parsers) == 5, "Wrong count"

# ✅ Good - Include actual value
assert len(parsers) == 5, f"Expected 5 parsers, got {len(parsers)}"

2. Explain Expected Behavior

❌ Bad - States the obvious:

assert {
  condition     = var.enabled == true
  error_message = "enabled is not true"
}

✅ Good - Explains why:

assert {
  condition     = var.enabled == true
  error_message = "Module must be enabled to create resources"
}

JavaScript:

// ✅ Custom message explains why
expect(module.enabled).toBe(true); // Use .toBe() for clarity

3. Reference External Documentation

Terraform:

assert {
  condition     = contains(["ECSServiceAverageCPUUtilization", "ALBRequestCountPerTarget"], var.metric_type)
  error_message = "Invalid metric type. See https://docs.aws.amazon.com/autoscaling/application/APIReference/API_PredefinedMetricSpecification.html"
}

JavaScript:

expect(['CPU', 'Memory'].includes(metricType))
  .toBe(true)
  .toThrow('Invalid metric. See AWS docs: https://...');

Assertion Types

1. Equality Assertions

Strict Equality:

// JavaScript
expect(value).toBe(expected);           // ===
expect(value).toStrictEqual(expected);  // Deep equality

// Python
assert value == expected
assert value is expected  # Identity check

// Go
assert.Equal(t, expected, value)
assert.Same(t, expected, value)  // Pointer equality

Terraform:

assert {
  condition     = aws_s3_bucket.bucket.bucket == "expected"
  error_message = "Bucket name mismatch"
}

2. Truthiness Assertions

JavaScript:

expect(value).toBeTruthy();
expect(value).toBeFalsy();
expect(value).toBeNull();
expect(value).toBeUndefined();
expect(value).toBeDefined();

Python:

assert value
assert not value
assert value is None
assert value is not None

Terraform:

assert {
  condition     = var.value != null
  error_message = "Value must not be null"
}

3. Comparison Assertions

JavaScript:

expect(value).toBeGreaterThan(10);
expect(value).toBeGreaterThanOrEqual(10);
expect(value).toBeLessThan(100);
expect(value).toBeLessThanOrEqual(100);

Python:

assert value > 10
assert value >= 10
assert value < 100
assert 10 <= value <= 100  # Range check

Terraform:

assert {
  condition     = var.cpu >= 256 && var.cpu <= 16384
  error_message = "CPU must be between 256 and 16384"
}

4. Collection Assertions

Contains:

// JavaScript
expect(array).toContain(item);
expect(array).toContainEqual({ id: 1 });
expect(string).toContain('substring');

// Python
assert item in array
assert 'substring' in string
assert {'id': 1} in array

// Terraform
assert {
  condition     = contains(var.allowed_values, var.value)
  error_message = "Value not in allowed list"
}

Length:

// JavaScript
expect(array).toHaveLength(5);

// Python
assert len(array) == 5

// Terraform
assert {
  condition     = length(var.list) == 5
  error_message = "Expected 5 items"
}

Empty:

// JavaScript
expect(array).toHaveLength(0);
expect(object).toEqual({});

// Python
assert not array  # Empty list is falsy
assert array == []
assert dict == {}

5. Type Assertions

JavaScript:

expect(typeof value).toBe('string');
expect(value).toBeInstanceOf(Array);
expect(Array.isArray(value)).toBe(true);

Python:

assert isinstance(value, str)
assert isinstance(value, list)
assert type(value) == str

Terraform:

assert {
  condition     = can(regex("^arn:aws:", var.arn))
  error_message = "Value must be a valid ARN"
}

6. Pattern/Regex Assertions

JavaScript:

expect(string).toMatch(/pattern/);
expect(string).toMatch(/^arn:aws:/);

Python:

import re
assert re.match(r'^arn:aws:', string)

Terraform:

assert {
  condition     = can(regex("^[a-z0-9-]+$", var.name))
  error_message = "Name must contain only lowercase letters, numbers, and hyphens"
}

7. Exception/Error Assertions

JavaScript:

expect(() => {
  throwError();
}).toThrow();

expect(() => {
  throwError();
}).toThrow('Specific error message');

expect(() => {
  throwError();
}).toThrow(CustomError);

Python:

import pytest

with pytest.raises(ValueError):
    raise_error()

with pytest.raises(ValueError, match="specific message"):
    raise_error()

Terraform (expect_failures):

run "test_validation_fails" {
  command = plan

  variables {
    invalid_value = "wrong"
  }

  expect_failures = [
    var.input,
  ]
}

Null Safety

Terraform Null Safety

Use try() for potentially null values:

assert {
  condition     = try(aws_s3_bucket.bucket.lifecycle_rule[0].enabled, false) == true
  error_message = "Lifecycle rule should be enabled"
}

Check existence first:

assert {
  condition     = aws_s3_bucket.bucket.logging != null
  error_message = "Logging configuration is missing"
}

Use can() to check if operation succeeds:

assert {
  condition     = can(regex("^arn:", var.arn))
  error_message = "Invalid ARN format"
}

JavaScript Null Safety

Optional chaining:

expect(bucket?.logging?.enabled).toBe(true);

Nullish coalescing:

expect(bucket.logging ?? {}).toEqual({ enabled: true });

Explicit checks:

expect(bucket.logging).toBeDefined();
expect(bucket.logging.enabled).toBe(true);

Python Null Safety

Check for None:

assert bucket.logging is not None
assert bucket.logging.enabled is True

Use get() with default:

assert bucket.get('logging', {}).get('enabled') is True

Multiple Assertions

✅ Good - Related conditions in same test:

run "validate_s3_configuration" {
  assert {
    condition     = aws_s3_bucket.bucket.bucket == "test-bucket"
    error_message = "Invalid bucket name"
  }

  assert {
    condition     = aws_s3_bucket.bucket.versioning[0].enabled == true
    error_message = "Versioning should be enabled"
  }

  assert {
    condition     = aws_s3_bucket.bucket.server_side_encryption_configuration != null
    error_message = "Encryption should be configured"
  }
}

JavaScript:

test('validate S3 configuration', () => {
  expect(bucket.name).toBe('test-bucket');
  expect(bucket.versioning.enabled).toBe(true);
  expect(bucket.encryption).toBeDefined();
});

Separate Unrelated Assertions

✅ Better - Separate concerns:

test('bucket has correct name', () => {
  expect(bucket.name).toBe('test-bucket');
});

test('bucket has versioning enabled', () => {
  expect(bucket.versioning.enabled).toBe(true);
});

test('bucket has encryption configured', () => {
  expect(bucket.encryption).toBeDefined();
});

Advanced Assertion Patterns

1. Complex Object Matching

JavaScript:

expect(user).toMatchObject({
  id: expect.any(Number),
  email: expect.stringContaining('@'),
  createdAt: expect.any(Date)
});

Terraform:

assert {
  condition     = alltrue([
    contains(keys(local.user), "id"),
    contains(keys(local.user), "email"),
    can(regex("@", local.user.email))
  ])
  error_message = "User object structure invalid"
}

2. Collection Element Validation

Terraform - All elements match:

assert {
  condition     = alltrue([
    for parser in local.parsers :
    contains(keys(parser), "name")
  ])
  error_message = "All parsers must have name field"
}

JavaScript:

expect(parsers.every(p => 'name' in p)).toBe(true);

Python:

assert all('name' in p for p in parsers)

3. Conditional Validation

Terraform:

assert {
  condition     = var.enable_logging ? aws_s3_bucket.logs != null : true
  error_message = "Logging bucket required when enable_logging is true"
}

JavaScript:

if (config.enableLogging) {
  expect(logsBucket).toBeDefined();
}

4. Range Validation

Terraform:

assert {
  condition     = var.cpu >= 256 && var.cpu <= 16384 && var.cpu % 256 == 0
  error_message = "CPU must be between 256 and 16384 in increments of 256"
}

Python:

assert 256 <= cpu <= 16384, f"CPU {cpu} out of range"
assert cpu % 256 == 0, f"CPU {cpu} must be multiple of 256"

5. Uniqueness Validation

Terraform:

assert {
  condition     = length([for p in local.parsers : p.name]) == length(toset([for p in local.parsers : p.name]))
  error_message = "All parser names must be unique"
}

JavaScript:

const names = parsers.map(p => p.name);
expect(new Set(names).size).toBe(names.length);

Python:

names = [p['name'] for p in parsers]
assert len(names) == len(set(names)), "Parser names must be unique"

Negative Testing (Expect Failures)

Test That Validation Works

Terraform:

# Test valid value passes
run "valid_environment" {
  variables {
    environment = "dev"
  }
  # Should succeed
}

# Test invalid value fails
run "invalid_environment" {
  command = plan

  variables {
    environment = "invalid"
  }

  expect_failures = [
    var.environment,
  ]
}

JavaScript:

test('throws error for invalid environment', () => {
  expect(() => {
    validateEnvironment('invalid');
  }).toThrow('Environment must be dev, staging, or prod');
});

Python:

def test_invalid_environment():
    with pytest.raises(ValueError, match="Environment must be"):
        validate_environment('invalid')

Test Preconditions

Terraform:

run "test_precondition_fails" {
  command = plan

  variables {
    instance_type = "t1.micro"  # Deprecated
  }

  expect_failures = [
    aws_instance.web,
  ]
}

Assertion Anti-Patterns

❌ Testing Implementation Instead of Behavior

// Bad - tests implementation
expect(service.cache.get).toHaveBeenCalled();

// Good - tests outcome
expect(result).toBe('cached-value');

❌ Vague Error Messages

# Bad
assert {
  condition     = local.value == "expected"
  error_message = "Test failed"
}

# Good
assert {
  condition     = local.value == "expected"
  error_message = "Value should be 'expected' for proper configuration"
}

❌ Testing Multiple Unrelated Things

// Bad - failure doesn't indicate what's wrong
test('everything works', () => {
  expect(bucket.name).toBe('test');
  expect(user.email).toBe('test@example.com');
  expect(lambda.runtime).toBe('nodejs18.x');
});

// Good - separate concerns
test('bucket has correct name', () => {
  expect(bucket.name).toBe('test');
});

❌ Brittle Assertions

// Bad - breaks with any change
expect(result).toEqual({
  id: 1,
  name: 'John',
  email: 'john@example.com',
  createdAt: '2024-01-15T10:30:00Z',
  updatedAt: '2024-01-15T10:30:00Z',
  // ... 20 more fields
});

// Good - test what matters
expect(result).toMatchObject({
  id: expect.any(Number),
  name: 'John',
  email: expect.stringContaining('@')
});

Framework-Specific Matchers

Jest Matchers

// Truthiness
expect(value).toBeTruthy();
expect(value).toBeFalsy();
expect(value).toBeNull();
expect(value).toBeUndefined();

// Numbers
expect(value).toBeGreaterThan(10);
expect(value).toBeCloseTo(0.3); // Floating point

// Strings
expect(string).toMatch(/pattern/);
expect(string).toContain('substring');

// Arrays/Iterables
expect(array).toContain(item);
expect(array).toHaveLength(3);

// Objects
expect(object).toHaveProperty('key');
expect(object).toMatchObject({ key: 'value' });

// Exceptions
expect(() => fn()).toThrow();
expect(promise).rejects.toThrow();

// Async
await expect(promise).resolves.toBe('value');

Pytest Assertions

# Basic
assert expression
assert expression, "error message"

# Approximation
assert value == pytest.approx(0.3)

# Exceptions
with pytest.raises(ValueError):
    raise_error()

with pytest.raises(ValueError, match="pattern"):
    raise_error()

# Warnings
with pytest.warns(UserWarning):
    trigger_warning()

Go testify/assert

import "github.com/stretchr/testify/assert"

// Equality
assert.Equal(t, expected, actual)
assert.NotEqual(t, expected, actual)

// Truthiness
assert.True(t, value)
assert.False(t, value)
assert.Nil(t, value)
assert.NotNil(t, value)

// Strings
assert.Contains(t, "hello world", "hello")
assert.Regexp(t, regexp.MustCompile("^[a-z]+$"), value)

// Collections
assert.Len(t, array, 5)
assert.Contains(t, array, item)
assert.ElementsMatch(t, expected, actual)

// Panics
assert.Panics(t, func() { panic("error") })
assert.NotPanics(t, func() { /* safe code */ })

Best Practices Summary

Do's

Include actual values in error messagesExplain expected behavior, not just conditionTest one concern per assertion when possibleUse framework-specific matchers for clarityWrite negative tests for validationHandle null/undefined safelyGroup related assertions logicallyTest behavior, not implementation

Don'ts

Don't write vague error messagesDon't test unrelated things togetherDon't make assertions too brittleDon't test implementation detailsDon't ignore null safetyDon't duplicate test logic in assertionsDon't test what you've mocked

References

スコア

総合スコア

60/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

レビュー

💬

レビュー機能は近日公開予定です