DEV Community

Cover image for WET vs. DRY: Testing Principles You Should Know
artshllaku
artshllaku

Posted on

2

WET vs. DRY: Testing Principles You Should Know

In software development, writing clear and maintainable tests is as crucial as writing the code itself. Two commonly discussed principles in this context are WET (Write Everything Twice) and DRY (Don’t Repeat Yourself).

These principles help guide how we structure tests, balancing readability, maintainability, and efficiency. Let’s dive into what they mean, explore examples, and understand when to apply each approach.

📝 What is WET Testing?

WET testing is a style where repetition in test cases is allowed. While often seen as less ideal, this approach can prioritize simplicity and clarity—particularly for straightforward tests.

Pros of WET Tests:

  • Simplicity: Easy to read and understand, especially for newcomers.
  • Isolation: Each test stands on its own, avoiding dependencies.
  • Quick to Write: Ideal for smaller projects or simpler scenarios.

Example of WET Testing:

describe('Login Tests - WET', () => {
  test('should allow user to login with valid credentials', async () => {
    await page.goto('https://example.com/login');
    await page.fill('input[name="username"]', 'user1');
    await page.fill('input[name="password"]', 'password1');
    await page.click('button[type="submit"]');
    await expect(page).toHaveURL('https://example.com/dashboard');
  });

  test('should show an error with invalid credentials', async () => {
    await page.goto('https://example.com/login');
    await page.fill('input[name="username"]', 'user1');
    await page.fill('input[name="password"]', 'wrongpassword');
    await page.click('button[type="submit"]');
    await expect(page).toHaveText('Invalid username or password');
  });
});
Enter fullscreen mode Exit fullscreen mode

In this example, the login steps are repeated across tests.

✨ What is DRY Testing?

DRY testing focuses on minimizing redundancy by abstracting shared logic into reusable functions or setups. This approach shines in complex or large projects.

Pros of DRY Tests:

  • Reduced Redundancy: Centralizes logic, avoiding repetition.
  • Ease of Maintenance: Changes only need to be made in one place.
  • Cleaner Code: Focuses tests on behavior rather than setup.

Example of DRY Testing:

describe('Login Tests - DRY', () => {
  const login = async (username, password) => {
    await page.goto('https://example.com/login');
    await page.fill('input[name="username"]', username);
    await page.fill('input[name="password"]', password);
    await page.click('button[type="submit"]');
  };

  test('should allow user to login with valid credentials', async () => {
    await login('user1', 'password1');
    await expect(page).toHaveURL('https://example.com/dashboard');
  });

  test('should show an error with invalid credentials', async () => {
    await login('user1', 'wrongpassword');
    await expect(page).toHaveText('Invalid username or password');
  });
});
Enter fullscreen mode Exit fullscreen mode

Here, the login function centralizes the shared steps, making the tests cleaner and easier to maintain.

💡 When to Use WET vs. DRY?

From personal experience, choosing between WET and DRY depends on your project’s complexity and requirements.

Use WET when:

  • Your tests are simple and isolated.
  • The code is unlikely to change frequently.
  • You prioritize clarity over abstraction.

Use DRY when:

  • You have repeated logic across multiple tests.
  • The codebase is large and maintainability is a concern.
  • You need to refactor tests for efficiency.

🔑 Key Takeaways
While the DRY principle is generally preferred, WET tests have their place. Strive for a balance that enhances both clarity and maintainability. For smaller projects or straightforward scenarios, a WET approach might suffice. However, in larger, more complex test suites, adopting DRY can significantly improve your workflow.

Ultimately, the goal is to write tests that are clear, maintainable, and efficient—whatever approach gets you there!

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read full post →

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Dive into an ocean of knowledge with this thought-provoking post, revered deeply within the supportive DEV Community. Developers of all levels are welcome to join and enhance our collective intelligence.

Saying a simple "thank you" can brighten someone's day. Share your gratitude in the comments below!

On DEV, sharing ideas eases our path and fortifies our community connections. Found this helpful? Sending a quick thanks to the author can be profoundly valued.

Okay