Introduction to Dependencies in Testing

Welcome to the first lesson of our course on managing test doubles. In this lesson, we will explore the concept of dependencies in software testing and introduce you to the use of test doubles, starting with "dummies," the simplest form of a test double.

Dependencies are components or services that your software relies on to function, like databases, logging systems, or external APIs. However, when testing, these dependencies can introduce variability, making it hard to test your code's logic reliably. Test doubles allow you to replace these real dependencies with simpler objects that mimic their behavior. This ensures tests focus solely on your code's logic without interference from external systems. For instance, by isolating an email service’s logging component using a test double, you can test email-related functionality without generating actual log entries.

During this course, we'll discuss five kinds of test doubles:

  • Dummies: Simple placeholders used to fulfill parameter requirements. They have no logic or behavior beyond satisfying an interface or method signature.
  • Stubs: Provide predefined responses to specific calls during testing, allowing you to control the behavior of certain dependencies without implementing full functionality.
  • Spies: Track information about interactions with dependencies, such as method calls and arguments, enabling you to verify behaviors indirectly.
  • Mocks: More sophisticated test doubles that are both stubs and spies. They allow you to set expectations and verify that certain interactions occur during testing.
  • Fakes: Simpler implementations of complex behavior that are useful for testing, typically with some working logic, often used to simulate a real system or component.

In this lesson, you'll learn how dummies provide a straightforward way to address dependencies by serving as simple placeholders without any logic. By the end, you'll have a foundational understanding of how to utilize dummies in your workflow, paving the way for more complex test doubles in future lessons.

Example of Using Dummies

Let's see dummies in action by setting up tests for an EmailService application using ScalaTest. Below is how you might create an EmailServiceSpec.scala file with dummies, using Scala 3 syntax:

class EmailServiceSpec extends AnyFunSpec with BeforeAndAfter:

  private var emailService: EmailService = uninitialized

  before:
    emailService = EmailService(DummyLogger(), DummyEmailSender())

  describe("EmailService"):

    it("should accept valid email parameters"):
      val result = emailService.sendEmail(
        "test@example.com",
        "Hello",
        "This is a test"
      )
      result.shouldBe(true)

In this example:

  • DummyLogger and DummyEmailSender act as stand-ins for real implementations. They don't have any behavior; they just satisfy the interface requirements of EmailService.
  • By using dummies, you reduce complexity and ensure that the tests are focusing solely on the logic within EmailService.

This method provides an introduction to isolating dependencies with minimal effort, setting the stage for learning about more advanced test doubles like stubs, mocks, and fakes.

In the example with EmailService, DummyLogger and DummyEmailSender are dummies that help isolate the service’s functionality. Rather than implementing actual logging or email-sending behavior, they simply fulfill the ILogger and IEmailSender traits required by EmailService. This approach keeps the test setup lightweight and efficient, focusing solely on the email parameter validation logic. By avoiding real actions, such as logging to a file or sending emails, tests run faster and remain focused on validating the core functionality of the EmailService.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal