I want to unit test a controller method that returns an EssentialAction. I pass a FakeRequest to it, and get back a Iteratee[Array[Byte], Result].
It looks like the test helpers contentAsString, contentType and status do not accept this result type.
Is there an implicit conversion I am missing? Is there an example somewhere of controllers being unit tested without bringing up an entire FakeApplication?
An essential action is a RequestHeader => Iteratee[Indata, Result], you can apply it to FakeRequest since it implements RequestHeader. To actually execute the iteratee you either stuff it with data or just tell it right away that there is no more indata. For both those cases you get a Future[Result] back which you need to wait for in the tests.
So, for a simple GET with no request body (using the play test helper await method) you could do it like this:
val iteratee = controllers.SomeController.action()(FakeRequest())
val result: Result = await(iteratee.run)
If you want to do requests with request bodies you will have to do some more stuff to be able to feed the request body to the iteratee and also take care of encoding data your indata correctly.
In Play 2.3, PlaySpecification includes a couple of helper methods. In order to handle EssentialActions, you'd use call. The resulting future is handled by other more specific helpers.
class MySpec extends PlaySpecification {
...
val result1: Result = call(controllers.SomeController.action(), FakeRequest(...))
status(of = result1) must equalTo (OK)
...
val result2 = call(controllers.SomeController.action(), RequestHeader(...), "Body")
status(of = result2) must equalTo (BAD_REQUEST)
}
Related
Say I've got a controller with an action that receives two parameters.
It invokes two services, one with each parameter, the services both return strings
each of those strings are passed as arguments to a template
the result is passed to Ok and returned.
I want to write a simple unit test that ensures:
1 - The correct services are invoked with the correct parameters
2 - The return values from the services are passed to the correct attributes of the template
What is the best way to do that?
Using Mockito with Specs2, I mock services to verify their method calls.
My controller is instantiated by Spring. That allows me to treat it is as a class instead of object. => That is essential to make controller testable. Here an example:
#Controller
class MyController #Autowired()(val myServices: MyServices) extends Controller
To enable Spring for controllers, you have to define a Global object, as the Play! documentation explains:
object Global extends GlobalSettings {
val context = new ClassPathXmlApplicationContext("application-context.xml")
override def getControllerInstance[A](controllerClass: Class[A]): A = {
context.getBean(controllerClass)
}
}
My unit test doesn't need Spring; I just pass collaborators (mocks) to constructor.
However, concerning the rendered template, I test only for the type of result (Ok, BadRequest, Redirection etc...).
Indeed, I noticed it's not easy at all to make my test scan the whole rendered template in details (parameters sent to it etc..), with only unit testing.
Thus, in order to assert that the right template is called with the right arguments, I trust my acceptance tests running Selenium, or a possible functional test, if you prefer, to scan for the whole expected result.
2 - The return values from the services are passed to the correct
attributes of the template
It's pretty easy to check for that..How? By trusting compiler! Prefer to pass some custom types to your template instead of simple primitives for instance:
phone: String would become: phone: Phone. (a simple value object).
Therefore, no fear to pass the attributes in a non-expected order to your template (in unit test or real production code). Compiler indeed will warn.
Here's an example of one of my unit test (simplified) using specs2:
(You will note the use of a wrapper: WithFreshMocks).
This case class would allow to refresh all variables (mocks in this case) test after test.
Thus a good way to reset mocks.
class MyControllerSpec extends Specification with Mockito {
def is =
"listAllCars should retrieve all cars" ! WithFreshMocks().listAllCarsShouldRetrieveAllCars
case class WithFreshMocks() {
val myServicesMock = mock[MyServices]
val myController = new MyController(myServicesMock)
def listAllCarsShouldRetrieveAllCars = {
val FakeGetRequest = FakeRequest() //fakeRequest needed by controller
mockListAllCarsAsReturningSomeCars()
val result = myController.listAllCars(FakeGetRequest).asInstanceOf[PlainResult] //passing fakeRequest to simulate a true request
assertOkResult(result).
and(there was one(myServicesMock).listAllCars()) //verify that there is one and only one call of listAllCars. If listAllCars would take any parameters that you expected to be called, you could have precise them.
}
private def mockListAllCarsAsReturningSomeCars() {
myServicesMock.listAllCars() returns List[Cars](Car("ferrari"), Car("porsche"))
}
private def assertOkResult(result: PlainResult) = result.header.status must_== 200
}
So, I came up with a cake pattern and mockito based solution:
given the service:
trait Service {
def indexMessage : String
}
trait ServiceImpl {
def indexMessage = {
"Hello world"
}
}
Then the controller looks like:
object Application extends ApplicationController
with ServiceImpl {
def template = views.html.index.apply
}
trait ApplicationController extends Controller
with Service {
def template: (String) => play.api.templates.Html
def index = Action {
Ok(template("controller got:" + indexMessage))
}
}
And the test looks like:
class ApplicationControllerSpec extends Specification with Mockito {
"cake ApplicationController" should {
"return OK with the results of the service invocation" in {
val expectedMessage = "Test Message"
val m = mock[(String) => play.api.templates.Html]
object ApplicationControllerSpec extends ApplicationController {
def indexMessage = expectedMessage
def template = m
}
val response = ApplicationControllerSpec.index(FakeRequest())
status(response) must equalTo(OK)
there was one(m).apply(Matchers.eq("controller got:" + expectedMessage))
}
}
}
I had a lot of trouble getting Mockito working.
It requires an extra dependency and I had a lot of trouble working out how to use the matchers in scala (I'm quite comfortable using it in java)
Ultimately I think the above answer is better, avoid using String and other primitive types where you can wrap them in task specific types, then you get compiler warnings.
Also I would generally avoid doing things like the "controller got:" prefixing in the controller.
It's there in this case so I can verify that it went through, in the real world that should be done by some other component (controllers are just for plumbing IMO)
I'm having a bit of a tough time trying to understand how to write tests in Scala when implicit parameters are involved.
I have the following (short version) of my code and test:
Implementation (Scala 2.10, Spray and Akka):
import spray.httpx.SprayJsonSupport._
import com.acme.ResultJsonFormat._
case class PerRequestIndexingActor(ctx: RequestContext) extends Actor with ActorLogging {
def receive = LoggingReceive {
case AddToIndexRequestCompleted(result) =>
ctx.complete(result)
context.stop(self)
}
}
object ResultJsonFormat extends DefaultJsonProtocol {
implicit val resultFormat = jsonFormat2(Result)
}
case class Result(code: Int, message: String)
Test (Using ScalaTest and Mockito):
"Per Request Indexing Actor" should {
"send the HTTP Response when AddToIndexRequestCompleted message is received" in {
val request = mock[RequestContext]
val result = mock[Result]
val perRequestIndexingActor = TestActorRef(Props(new PerRequestIndexingActor(request)))
perRequestIndexingActor ! AddToIndexRequestCompleted(result)
verify(request).complete(result)
}
}
This line, verify(request).complete(result) uses an implicit Marshaller to turn Result into JSON.
I can bring a marshaller in to scope by adding implicit val marshaller: Marshaller[Result] = mock[Marshaller[Result]] but when I run the test a different instance of Marshaller is used, so the verification fails.
Even explicitly passing the mock Marshaller to complete fails.
So, can any one advise how to create a mock object for an implicit parameter and make sure that instance is the one used?
This is a perfect situation to use a Matcher from Mockito for the marshaller arg. You should not need to mock out the implicit marshaller. All you really want to do is verify that complete was called with a result matching what you expected and also some instance of the marshaller. First, if you haven't already done it, bring the Mockito matchers into scope with an import like so:
import org.mockito.Matchers._
Then, if you wanted reference matching on the result, you could verify like so:
verify(request).complete(same(result))(any[classOf[Marshaller[Result]]])
Or, if you wanted equals matching on result you could do:
verify(request).complete(eq(result))(any(classOf[Marshaller[Result]]))
The trick with matchers is that once you use one for one arg, you have to use them for all args, so that's why we have to use one for result too.
We are trying to unit test code that relies on the Entity Framework 4.1. I've seen several posts that implement unit testing against POCOs, but we would like to retain the default EF plumbing, so that we can easily use the EF Caching Wrapper.
FakeItEasy seems to handle abstracting away EF okay, but I'm having problems asserting what happened. For example, I have this code in my model (where there is another Email partial class that is the autogenerated code from the EF database-first wizard):
public partial class Email
{
IMyEntities _dataContext;
public Email(IMyEntities myEntities)
{
_dataContext = myEntities;
}
public void SendEmails()
{
// ... code to send emails goes here...
_dataContext.Emails.AddObject(this);
_dataContext.SaveChanges();
}
}
Then in my unit test with FakeItEasy:
var context = A.Fake<IMyEntities>();
var email = A.Fake<Email>(context);
// ... code to configure email goes here ...
email.SendEmails();
// this fails with a FakeItEasy.ExpectationException...
A.CallTo(() => context.Email.AddObject(email)).MustHaveHappened();
How can I know from my unit test that context.Emails.AddObject actually did get called?
Thank you!
You need to set the Email-property of you context to a fake:
var context = A.Fake<IMyEntities>();
var mail = A.Fake<WhateverTypeTheEmailPropertyHas>();
A.CallTo(() => context.Email).Returns(mail);
var email = A.Fake<Email>(context);
// ... code to configure email goes here ...
email.SendEmails();
// this fails with a FakeItEasy.ExpectationException...
A.CallTo(() => mail.AddObject(email)).MustHaveHappened();
Now I guess it should work.
I found a workaround that I'm not crazy about, but it does work. Instead of calling AddObject() on the child object, you can call a deprecated method, AddTo[Collection Name](), on the data context itself. Since this is just a shallow method call, it can be easily evaluated by FakeItEasy.
My code changed to this:
public void SendEmails()
{
// ... code to send emails goes here...
_dataContext.AddToEmails(this);
_dataContext.SaveChanges();
}
Then, in my unit test:
A.CallTo(_dataContext).Where(m => m.Method.Name == "AddToEmails").MustHaveHappened();
A.CallTo(() => _dataContext.SaveChanges()).MustHaveHappened();
Of course, by doing this you have the downside of always ignoring the preferred, non-deprecated, methods whenever you want to add to a collection of the data context. Not to mention, there's a good chance I'll get tripped up later on with a need to determine execution on a child object's method...
If anyone knows a better way, please share!
Thank you,
Eric
Is it possible to mock a stub/mock's object member call without having to define that as a stub, and also set the return value as all seperate verbose lines?
Example:
[TestMethod]
public void AssignedPermissions_AssociateExists_ReturnsEdit_Rhino()
{
//Arrange
var fakeConfiguration = MockRepository.GenerateStub<IDomainControllerConfiguration>();
var fakeAssociateRepository = MockRepository.GenerateStub<IAssociateRepository>();
fakeConfiguration.Stub(x => x.AssociateRepository).Return(fakeAssociateRepository);
fakeAssociateRepository.Stub(x=>x.GetAssociatesByRole(null,false,null)).IgnoreArguments()
.Return(new IAssociate[]{MockRepository.GenerateStub<IAssociate>()});
var domain = new DomainController(fakeConfiguration);
const AssignedPermission expected = AssignedPermission.Edit;
//Act
AssignedPermission actual = domain.AssignedPermissions();
//Assert
Assert.AreEqual(expected, actual);
}
Are all those temporary variables necessary just to stub out nested method calls?
I've never used the functionality, so I'm not 100% certain that this will work, but theoretically Rhino mocks supports "recursive mocking", which should allow you to at least cut out the fakeAssociateRepository by doing something like this:
var fakeConfiguration = MockRepository.GenerateStub<IDomainControllerConfiguration>();
fakeConfiguration.Stub(x => x.AssociateRepository.GetAssociatesByRole(null,false,null))
.IgnoreArguments()
.Return(new IAssociate[]{MockRepository.GenerateStub<IAssociate>()});
var domain = new DomainController(fakeConfiguration);
(note: code not tested, or even compiled)
Just wanted to share my input on this, since I just spent the last few hours wrestling with it. The answer posted above by Alconja absolutely works, but if you plan to use it for "AssertWasCalled" type of assertion, it does not assert the way I expected it to. It seems that the AssertWasCalled methods tried to assert the "get accessor" associated with the "nested" object.
For instance, if you wanted to do this:
fakeconfiguration.AssertWasCalled(x => x.AssociateRepository.GetAssociatesByRole(null, false, null));
You would get an exception such as
System.InvalidOperationException : Previous method 'IDomainControllerConfiguration.get_AssociateRepository();' requires a return value or an exception to throw.
Because the AssertWasCalled is asserting the get-accessor of the AssociateRepository property, rather than the GetAssociatesByRole() method. In the end, for my case I had to use the OP's methodology of creating mutliple stubs.
The test class below verifies that a simple HttpService gets content from a given URL. Both the implementations shown make the test pass, though one is clearly wrong because it constructs the URL with an incorrect argument.
To avoid this and correctly specify the behaviour I want, I'd like to verify that in the use block of the test case, I construct one (and only one) instance of the URL class, and that the url argument to the constructor is correct. A Groovy enhancement seems like it would let me add the statement
mockURLContext.demand.URL { assertEquals "http://www.foo.com", url }
but what can I do without that Groovy enhancement?
Update: Replaced "mock" with "stub" in the title, as I'm only interested in checking the state not necessarily the detail of the interactions. Groovy has a StubFor mechanism that I haven't used, so I'll leave my code as is, but I think you could just replace MockFor with StubFor throughout.
import grails.test.*
import groovy.mock.interceptor.MockFor
class HttpServiceTests extends GrailsUnitTestCase {
void testGetsContentForURL() {
def content = [text : "<html><body>Hello, world</body></html>"]
def mockURLContext = new MockFor(URL.class)
mockURLContext.demand.getContent { content }
mockURLContext.use {
def httpService = new HttpService()
assertEquals content.text, httpService.getContentFor("http://www.foo.com")
}
}
}
// This is the intended implementation.
class HttpService {
def getContentFor(url) {
new URL(url).content.text
}
}
// This intentionally wrong implementation also passes the test!
class HttpService {
def getContentFor(url) {
new URL("http://www.wrongurl.com").content.text
}
}
What does mocking the URL get you? It makes the test difficult to write. You won't be able to react to feedback the mock objects give you about the design of the API of the URL class, because it's not under your control. And if you don't precisely fake the behaviour of the URL and what it exposes about the HTTP protocol, the test will not be reliable.
You want to test that your "HttpService" object actually loads the data correctly from a given URL, copes with different content type encodings correctly, handles different classes of HTTP status code appropriately, and so forth. When I need to test this kind object -- one that merely wraps some underlying technical infrastructure -- I write a real integration test that verifies that the object really does use the underlying technology correctly.
For HTTP I write a test that creates an HTTP server, plugs a servlet into the server that will return some canned data, passed the URL of the servlet to the object to make it load the data, check that the loaded result is the same as the canned data used to initialise the servlet, and stop the server in the fixture tear-down. I use Jetty or the simple HTTP server that is bundled with JDK 6.
I'd only use mock objects to test the behaviour of objects that talk to the interface(s) of that object I've integration tested.
Putting on my "Programming in the Small" and "Unit test 100%" hat, you could consider this as a single method that does too many things. You could refactor the HttpService to:
class HttpService {
def newURLFrom(urlString) {
new URL(urlString)
}
def getContentText(url) {
url.content.text
}
def getContentFor(urlString) {
getContentText(newURLFrom(urlString))
}
}
This would give you a few more options for testing, as well as split out the factory aspect from the property manipulation. The testing options are bit more mundane then:
class HttpServiceTests extends GroovyTestCase {
def urlString = "http://stackoverflow.com"
def fauxHtml = "<html><body>Hello, world</body></html>";
def fauxURL = [content : [text : fauxHtml]]
void testMakesURLs() {
assertEquals(urlString,
new HTTPService().newURLFrom(urlString).toExternalForm())
}
void testCanDeriveContentText() {
assertEquals(fauxHtml, new HTTPService().getContentText(fauxURL));
}
// Going a bit overboard to test the line combining the two methods
void testGetsContentForURL() {
def service = new HTTPService()
def emc = new ExpandoMetaClass( service.class, false )
emc.newURLFrom = { input -> assertEquals(urlString, input); return fauxURL }
emc.initialize()
service.metaClass = emc
assertEquals(fauxHtml, service.getContentFor(urlString))
}
}
I think that this makes all the assertions that you want, but at the cost of sacrificing test readability in the last case.
I would agree with Nat about this making more sense as an integration test. (You are integrating with Java's URL library on some level.) But assuming that this example simplifies some complex logic, you could use the metaclass to override the instances class effictvely partially mocking the instance.
It's tough to mock out JDK classes that are declared final... Your problem, as you reference through the enhancement, is that there is no way to create a URL other than calling the constructor.
I try to separate the creation of these kinds of objects from the rest of my code; I'd create a factory to separate the creation the URLs. This should be simple enough to not warrant a test. Others take a typical wrapper/decorator approach. Or you may be able to apply the adapter pattern to translate to domain objects that you write.
Here is a similar answer to a surprisingly similar problem: Mocking a URL in Java
I think this demonstrates something that a lot of people learn after doing more testing: the code we write to make things more testable is meant to isolate what we desire to test from what we can safely say is already tested somewhere else. It's a fundamental assumption we have to make in order to do unit testing. It can also provide a decent example of why good unit tests aren't necessarily about 100% code coverage. They have to be economical, too.
Hope this helps.
What exactly are you expecting to have fail? It is not readily apparent what you are trying to test with that code. By Mocking URL.getContent you are telling Groovy to always return the variable content when URL.getContent() is invoked. Are you wishing to make the return value of URL.getContent() conditional based upon the URL string? If that is the case, the following accomplishes that:
import grails.test.*
import groovy.mock.interceptor.MockFor
class HttpServiceTests extends GrailsUnitTestCase {
def connectionUrl
void testGetsContentForURL() {
// put the desired "correct" URL as the key in the next line
def content = ["http://www.foo.com" : "<html><body>Hello, world</body></html>"]
def mockURLContext = new MockFor(URL.class)
mockURLContext.demand.getContent { [text : content[this.connectionUrl]] }
mockURLContext.use {
def httpService = new HttpService()
this.connectionUrl = "http://www.wrongurl.com"
assertEquals content.text, httpService.getContentFor(this.connectionUrl)
}
}
}