I have seen multiple questions regarding as how to mock a companion object with frequently mentioned answer being to use scalamock but according to the doc for version 3, mocking companion objects is still marked for future.
So what is the way to mock a companion object? If not is there a better way to do things than what I already have to enable testing?
Code using play framework:
Model
case class Article(id: String, preview: String)
object Article {
def get(id: String) = {
......
}
}
ArticleResource
class ArticleResource extends Controller {
def getArticle(id: String) = authenticate {
......
Article.get(id)
......
}
}
How do I mock Article.get(id)?
Before when I had it working, I had structured the code differently:
Approach for working tests
Model
case class Article(id: String, preview: String)
Service
class ArticleService {
def get(id: String) = {
......
}
}
object ArticleService {
def apply = new ArticleService
}
ArticleResource
class ArticleResource(articleService: ArticleService) {
def getArticle(id: String) = authenticate {
......
articleService.get(id)
......
}
}
object ArticleResource extends controllers.ArticleResource(ArticleService())
In the test I injected a mock[ArticleService] into the Resource for testing.
I kept hearing the former approach (models) is the "right" approach, I never understood why so I tried it and ran into problems into testing and still I do not understand why it is the better approach. (I am actually feeling more strongly towards the latter approach now considering the difficulties with testing)
So I have 2 questions:
Is there a way to mock companion object?
Is there a "right" approach as how code is structured and if so why?
1) I don't think it's possible, and I don't think it's a good idea. I don't think it's desirable to put behavior-that-you-need-to-mock in companion objects.
2) I also believe that your first approach was better. If you want to keep your current code with minimal changes, how about that:
case class Article(id: String, preview: String)
object Article {
def get(id: String) = {
......
}
}
class ArticleResource(articleFinder: (String) => Article = Article.get) {
def getArticle(id: String) = authenticate {
......
articleFinder(id)
......
}
}
And when testing ArticleResource you can just create a function String => Article of your choice. You don't even need a framework for that :)
Edit: You can even use the companion object's method as default value to make it easier to instantiate in production code.
Related
I have been trying to figure this out for 2 days now and I am really stuck and frustrated. I have a domain object with a service which is being used for custom validation. The domain looks like this:
class Llama {
String name
transient myFetcherService
static transients = [
'myFetcherService'
]
static constraints = {
name validator: { val, obj ->
if (obj.nameExists(val) == true) {
//return some error here.
}
}
}
protected boolean nameExists(String name) {
List<Llama> llamasList = myFetcherService.fetchExistingLlamasByName(name)
if (llamasList.isEmpty()) {
return false
}
return true
}
}
Now, I have another Service, which simply saves a list of Llama objects. It looks like this:
class LlamaFactoryService {
public void createLlamas(List<String> llamaNames) {
llamaNames.each { name ->
new Llama(name: name).save()
}
}
}
In my test. I keep getting this error:
Failure: createLlamas should create Llammas (com.myLlamaProject.LlamaFactoryServiceSpec)
| java.lang.NullPointerException: Cannot invoke method myFetcherService on null object
I don't understand. In my tests, added a metaClass for the service in the "given" section. When it tries to save, it's telling that the service is null. This is what my test looks like:
given:
def myFetcherService = mockFor(MyFetcherService)
myFetcherService.demand.fetchExistingLlamasByName {def name -> return []}
Llama.metaClass.myFetcherService = myFetcherService.createMock()
when:
service.createLlamas(['Pablo','Juan','Carlos'])
then:
//some validations here....
I also tried using metaClass on the method nameExists() like:
Llama.metaClass.myFetcherService = { def name -> false }
, but it gives me the same nullPointerException as the one above. Could someone point me to the right direction? I'm a bit stuck. :(
Thanks in advance for reading and helping.
You're using a unit test and the general rule for unit tests is that beans generally aren't created for you, so you'll need to inject them yourself.
(Code edited to reflect the fact I misread the question)
I think you want a testing pattern something like:
given:
def mockMyFetcherService = Mock(MyFetcherService) // create the mock
Llama.metaClass.getMyFetcherService = { mockMyFetcherService } // inject the dependency
def returnList = [] // let's just define this here and you can re-use this pattern in other tests more easily
when:
service.createLlamas(['Pablo','Juan','Carlos'])
then:
// tell Spock what you expect to have happen with your Mock - return the List you defined above
3 * mockFetcherService.fetchExistingLlamasByName(_) >> returnList
If the injection of the service into the metaClass doesn't work (suggested here), you could always try using the defineBeans{} closure within the unit test itself (http://www.block-consult.com/blog/2011/08/17/inject-spring-security-service-into-domain-class-for-controller-unit-testing/).
Thus you could try:
defineBeans {
myFetcherService(MockMyFetcherService)
}
where MockMyFetcherService is defined in the same file that defines the test. This is the approach followed here:
See here for examples of more Spock interactions.
If you're using Grails 2.4.3 or below you'll need to put CGLIB in BuildConfig.groovy but I see here that it's already done for you in 2.4.4, so you should be ok just to use Mock(classname).
I have some (Scala) code in Play which uses JPA for DB access. Works fine. But I want to unit test my code, which will require using a mock EntityManager. Is this possible?
My test is written in specs2 (by extending PlaySpecification) and is run with JUnit. I am using Mockito to mock the EntityManager. But I would expect to be able to do this with other frameworks.
Here's what my code looks like:
object MyThing {
def create(...) : MyThing = {
val newThing = ...
JPA.withTransaction(new play.libs.F.Function0[Unit]() {
def apply() = {
JPA.em().persist(newThing)
}
})
return newThing
}
}
If it is not possible to unit test this code, is there some alternate approach to data access which is recommended?
Apparently there is no way to use a mock EntityManager here, at least none that I could find. So I had to revise my design.
Will Sargent of Typesafe suggested creating a separate DB persistence subproject on the mailing list: https://groups.google.com/d/msg/play-framework/1u-_JbTIuQg/L5_9o4YCfoMJ. I haven't gone quite that far, but I did find a solution that worked for me by defining a separate DAO interface.
I put all the JPA code into a DAO trait - all the implementation is in there. There's also a companion object to provide a singleton instance. Like so:
trait MyThingDAO {
def create(...) : MyThing = { ... }
}
object MyThingDAO extends MyThingDAO
Now I change my controllers to traits, with a reference to the DAO left unset. A companion object sets the DAO instance to the singleton object. This avoids making any changes to the routes file (no need to instantiate the controllers). Like so:
trait MyThingController {
val myThingDao : MyThingDAO
def myAction = Action { implicit request => ... }
}
object MyThingController {
val myThingDao = MyThingDAO
}
So everything works easily enough with the standard JPA code when the app is running. But when I want to unit test, I can insert a mock DAO like so (this is using Mockito):
...
val mockDao = mock[MyThingDAO]
val controller = new MyThingController() { val myThingDao = mockDao }
...
Maybe this isn't the ideal approach, but it has been working so far. I would still be interested to hear any other suggestions.
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 sure this is a fairly common situation. I'm using the Spring Security Core plugin and want to create a domain model that has a Person limited to certain roles:
class Workgroup {
Person manager
...
static constraints = {
manager(validator: {mgr ->
// it feels like there should be a more elegant, groovy way of doing this.
def auths = mgr.getAuthorities();
def returny = false
auths.each {
if(it.authority == 'ROLE_MANAGER')
{
returny = true
}
}
return returny
})
}
}
This test fails like a mofo:
void testInvalidManager() {
def nick = new Person(username:'Nick')
def nonManagerRole = new Role(authority:'ROLE_EMPLOYEE')
UserRole.create(nick,nonManagerRole)
def awesome = new Workgroup(name:'mooCows', manager:nick)
mockForConstraintsTests(Workgroup, [awesome])
assertFalse awesome.validate()
assertEquals "validator", awesome.errors["manager"]
}
testInvalidManager Error No signature of method: users.UserRole.save() is applicable for argument types: (java.util.LinkedHashMap) values: [[flush:false, insert:true]] Possible solutions: wait(), any(), wait(long), use([Ljava.lang.Object;), isCase(java.lang.Object), each(groovy.lang.Closure)
groovy.lang.MissingMethodException: No signature of method: users.UserRole.save() is applicable for argument types: (java.util.LinkedHashMap) values: [[flush:false, insert:true]]
Possible solutions: wait(), any(), wait(long), use([Ljava.lang.Object;), isCase(java.lang.Object), each(groovy.lang.Closure)
at users.UserRole.create(UserRole.groovy:32)
at users.UserRole.create(UserRole.groovy)
at users.UserRole$create.call(Unknown Source)
at users.WorkgroupTests.testInvalidManager(WorkgroupTests.groovy:17)
Is this better covered in Integration than Unit Testing? Do I need to mock UserRole (if so, how?)? How are these types of tests normally done?
UserRole.create() calls save(), so you need to use mockDomain() instead of just mockForConstraintsTests().
But that's only if you're ok with testing the domain model with mocks, which I would never do. The mocking support in Grails should be used when testing Controllers or other classes that use domain classes but shouldn't be bothered with real persistence, creating a database (even in-memory), etc. By removing that dependency you're concentrating on the current tier, trusting that the other tier is already properly tested. But when you use mocking to test domain classes, you're really just testing the mocking framework. So I always use integration tests for domain classes so they run against a real database.
To answer the implicit question from your code example, I'd write the constraint as
static constraints = {
manager validator: { mgr ->
mgr.authorities.find { it.authority == 'ROLE_MANAGER' } != null
}
}
The issue with its bulk is that you're using each() when a regular for loop would be preferable since you can return from a for loop. Use each() only when you really want to invoke the closure on every instance. Here's one that's less groovy than the other one but uses a for loop:
static constraints = {
manager validator: { mgr ->
for (auth in mgr.getAuthorities()) {
if (it.authority == 'ROLE_MANAGER') {
return true
}
}
return false
}
}
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)
}
}
}