Scala
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented Scala
-
Section 4: Functional Scala
-
Section 5: Collections in Depth
-
Section 6: Type System
-
Section 7: Concurrency and Ecosystem
-
Section 8: Practical Projects
-
Section 9: Interview Practice
-
Section 10: Data Structures and Algorithms in Scala
-
Section 11: More Practice Exercises
-
Section 12: Advanced Functional Patterns
-
Section 13: More Ecosystem
-
Section 14: Scala Collections Library Deep Dive
-
Section 15: Scala Standard Library Deep Dive
-
Section 16: Akka Ecosystem Deep Dive
-
Section 17: Cats and Cats Effect Deep Dive
-
Section 18: Play Framework Deep Dive
-
Section 19: Apache Spark with Scala Deep Dive
-
Section 20: Scala Build Tools Deep Dive
-
Section 21: Scala 3 Specific Features
-
90: Union and Intersection Types
-
Section 22: Scala Testing Deep Dive
-
Section 23: Functional Domain Modeling
-
Section 24: More Data Structures and Algorithms in Scala
-
Section 25: Scala for Data Engineering
-
Section 26: More Practical Projects
-
Section 27: More Interview and Review
-
Section 28: ZIO Ecosystem Deep Dive
-
Section 29: Scala for Machine Learning
-
Section 30: Scala Microservices Architecture
-
Section 31: Scala Type System Deep Dive
-
Section 32: More Practice and Drills
-
Section 33: Scala Performance Deep Dive
-
Section 34: Scala Ecosystem Tooling
-
Section 35: Scala for Reactive Systems
-
Section 36: More Real-World Case Studies
-
Section 37: Scala for Financial Systems
-
Section 38: Scala GraphQL and gRPC
-
Section 39: More Final Projects
-
Section 40: More Interview and Final Review
-
Section 41: Scala for Streaming Data
-
Section 42: Scala Security Practices
-
Section 43: More Language Deep Dive
-
Section 44: Scala Command-Line Tools
-
Section 45: Scala Documentation and Style
-
Section 46: Scala Dependency Management
-
Section 47: More Practical Backend Patterns
-
Section 48: Scala for Event-Driven Architecture
-
Section 49: More Practice Drills Round 2
-
Section 50: Scala Compiler Deep Dive
-
Section 51: Scala for Web Frontends
-
Section 52: More Data Engineering Practice
-
Section 53: Scala Observability
-
Section 54: More Advanced Practice Projects
-
Section 55: Scala for Legacy Java Integration
-
Section 56: More Testing Practice
-
Section 57: Final Mastery Review
-
Section 58: Scala History and Ecosystem Context
-
Section 59: More Concurrency Patterns
-
Section 60: Scala for Configuration Management
-
Section 61: More Domain Modeling Practice
96: Testing Akka Actors
How do I actually "see" what an actor is sending since they don't return values?
This is the first hurdle everyone hits with Akka. In a normal class, you call a method and check the return value. With actors, you send a message into a void and hope for the best. To test this, we use a TestProbe. Think of a probe as a "fake" actor that you control. You can tell it to expect a specific message, and if that message doesn't show up within a certain timeframe, the test fails.
Let's say we have a PaymentProcessor actor that sends a PaymentConfirmed message to a tracking actor. You don't want to spin up a whole tracking system just for a unit test. Instead, you do this:
import akka.testkit.{TestKit, TestProbe} import akka.actor.ActorSystem import org.scalatest.wordspec.AnyWordSpecLike class PaymentProcessorSpec extends TestKit(ActorSystem("PaymentSystem")) with AnyWordSpecLike { "A PaymentProcessor" should { "send a confirmation message after processing" in { val probe = TestProbe() // We pass the probe's ref instead of a real ActorRef val processor = system.actorOf(Props(new PaymentProcessor(probe.ref))) processor ! ProcessPayment(amount = 100) // This blocks until the message arrives or it times out probe.expectMsg(PaymentConfirmed(100)) } } }Do I have to use Thread.sleep to wait for the actor to finish?
Please, whatever you do, don't use
Thread.sleep(). I've seen far too many CI pipelines slowed to a crawl—or worse, made "flaky"—because someone added a 500ms sleep to a test. Actors are asynchronous, butTestProbehandles the waiting for you.Methods like
expectMsgorexpectMsgPF(the partial function version) are designed to poll the actor's mailbox. They wait just long enough for the message to arrive and then immediately proceed. If the message takes 2ms, the test takes 2ms. If it takes 2 seconds, it waits 2 seconds. It's much more efficient and reliable than guessing how long a thread needs to sleep.How do I test an actor that depends on other actors?
The secret here is dependency injection. Don't let your actor create its own dependencies using
context.actorOfinside the constructor if you want to test it easily. Instead, pass theActorRefs of those dependencies in as arguments. This allows you to swap a real actor for aTestProbeduring testing.Imagine an
OrderManagerthat needs to talk to anInventoryActor. If you hardcode theInventoryActor, you're testing two actors at once, which is an integration test, not a unit test. Here is how I usually structure it:class OrderManager(inventoryActor: ActorRef) extends Actor { def receive = { case PlaceOrder(item) => inventoryActor ! CheckStock(item) } } // In your test: val inventoryProbe = TestProbe() val orderManager = system.actorOf(Props(new OrderManager(inventoryProbe.ref))) orderManager ! PlaceOrder("Scala Book") inventoryProbe.expectMsg(CheckStock("Scala Book"))By doing this, you've isolated the
OrderManager. You aren't testing if the inventory system works—you're testing that theOrderManagerknows how to ask the inventory system for stock. That separation makes your tests run faster and makes it obvious where a bug actually lives.
📋 Practical Task
Test the NotificationDispatcher Actor
You are tasked with testing a NotificationDispatcher actor. This actor is responsible for sending a notification to two different services: an Email service and an SMS service. Whenever the dispatcher receives a SendAlert(message: String) command, it should send that exact message to both the email actor and the SMS actor.
Your Goal: Write a ScalaTest specification using Akka TestKit that verifies the NotificationDispatcher sends the correct message to both dependencies.
Requirements:
- Create two
TestProbeinstances (one for email, one for SMS). - Initialize the
NotificationDispatcherby passing in therefof both probes. - Send a
SendAlert("System Overload!")message to the dispatcher. - Use
expectMsgon both probes to ensure they both received the "System Overload!" string.
There are no comments for now.