Hello everyone,
I was hoping someone could give me some advice on unit testing when using Play! and external services.
Specifically, how do you test your code when it interacts with an external service that you don't want to have running when your tests are executing? Think along the lines of a message queue, an SMTP server, or a web service.
From what I've seen so far, Play! doesn't seem to have the concept of a service layer; I can't create a service and inject that into a controller because Play! uses static methods for its actions and so constructor injection isn't available.
Without constructor injection, my code looks like this:
public class User extends Controller {
public static void register() {
models.User user = new models.User(...);
user.save();
MessageQueue.publish(new UserCreatedMessage(user.id)); }
}
MessageQueue is static, how would I test interactions with that?
I could use Guice or Spring and inject into a static field, but that then necessitates using Guice in my tests and somehow supplying a mocked MessageQueue instance. I could probably live with doing that, but it doesn't feel as nice as using constructor injection.
Then there's the model approach. I understand the anaemic domain model argument, "put it in your model", which is fine, but then my model has a hard-dependency on a service which similarly cannot be replaced at test-time.
In Ruby and other dynamic languages this isn't really an issue. By all means, have your model reference an external service, you can just replace the call dynamically in the test. Sadly, this is Java and we don't have that option without resorting to something like PowerMock, which seems overkill.
With the model approach, it'd look something like this:
public class User extends Model {
@PostPersist
void onCreated() {
MessageQueue.publish(new UserCreatedMessage(this.id)); }
}
How would you test interactions with the MessageQueue without resorting to querying a real-live queue in your test?
Does Play! really not support truly isolated tests? What am I missing here? This seems like a fairly big issue to me. Integration tests are important, but I also feel you should be able to test in isolation, especially when it comes to dealing with external services.
Many thanks,
James