I'm trying to write some unit tests for a service in my Grails app. The service, 'MyService', uses a class located in $APP-ROOT/src/groovy/ called 'MyHelperClass'.
In the unit test for MyService, I try to create a mock for MyHelperClass like so:
def myHelperClassMock = mockFor(MyHelperClass)
def myService = new MyService()
myService.myHelperClass = myHelperClassMock.createMock()
This gives the error:
Error casting map to com.mycompany.myproject.MyHelperClass, Reason: Could not find matching constructor for: com.mycompany.myproject.MyHelperClass()
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Error casting map to com.mycompany.myproject.MyHelperClass, Reason: Could not find matching constructor for: com.mycompany.myproject.MyHelperClass()
at grails.test.GrailsMock.createMock(GrailsMock.groovy:91)
at grails.test.GrailsMock$createMock.call(Unknown Source)
at com.mycompany.myproject.MyServiceTests.testSomething(MyServiceTests.groovy:17)
This seems to happen only for classes in src/, and appears to work fine for classes in grails-app/services for example. Any idea how I can get it to see the classes in src/?
Thanks!
The code doesn't specify it, but createMock appears to require that the class being mocked have a default (no arguments) constructor.
The normal Grails artifacts under /grails-app all have these, whereas some other class under /src may not.
Adding a default constructor fixed the error when I ran into this.
Also see https://groups.google.com/forum/?fromgroups=#!topic/groovymn/u2Ng_RM224A for a related discussion of this.
This answer should give you the info you need.
Mocking out constructors in Grails
Related
I'm in the process of updating our test suite from OCMock 2 to OCMock 3 and am running into a few issues.
One of the issue is that we're trying to mock AVCaptureDeviceInput.
For one of the test we want to return a mocked instance AVCaptureDeviceInput when a class method is called on AVCaptureDeviceInput.
in our setup method:
self.mockAVCaptureDeviceInputClass = [OCMockObject mockForClass:[AVCaptureDeviceInput class]];
in our test:
id deviceInput = [OCMockObject mockForClass: [AVCaptureDeviceInput class]];
[[[[self.mockAVCaptureDeviceInputClass stub] classMethod] andReturn:deviceInput]
deviceInputWithDevice:mockDevice error:((NSError __autoreleasing **)[OCMArg setTo:nil])];
The issue seems to be that deviceInput overwrites the self.mockAVCaptureDeviceInputClass so that when the classMethod is stubbed, it does not do anything.
An alternative I tried to work around this was to create a mock for an instance of AVCaptureDeviceInput, but that just hangs:
[OCMockObject partialMockForObject: [AVCaptureDeviceInput new]];
with the following stack trace:
0x000000010938a219 in _object_set_associative_reference ()
0x0000000108aed5c3 in OCMSetAssociatedMockForClass at /Users/otusweb/Desktop/dfsa/Pods/OCMock/Source/OCMock/OCMFunctions.m:226
0x00000001144ecce2 in -[OCClassMockObject prepareClassForClassMethodMocking] at /Users/otusweb/Desktop/dfsa/Pods/OCMock/Source/OCMock/OCClassMockObject.m:89
0x00000001144ec934 in -[OCClassMockObject initWithClass:] at /Users/otusweb/Desktop/dfsa/Pods/OCMock/Source/OCMock/OCClassMockObject.m:31
0x00000001144f47f6 in -[OCPartialMockObject initWithObject:] at /Users/otusweb/Desktop/dfsa/Pods/OCMock/Source/OCMock/OCPartialMockObject.m:33
0x00000001144f1cdd in +[OCMockObject partialMockForObject:] at /Users/otusweb/Desktop/dfsa/Pods/OCMock/Source/OCMock/OCMockObject.m:58
0x00000001144e9abe in -[dfsaTests testExample] at /Users/otusweb/Desktop/dfsa/dfsaTests/dfsaTests.m:33
You are running into a common issue: only one mock object can mock class methods for a given class. This is is documented in the limitations section (http://ocmock.org/reference/#limitations). Currently the last mock created "wins".
What happens in your case is that you set up the first mock in your setup method (self.mockAVCaptureDeviceInputClass) but then you create a second mock for the same class in your test (deviceInput). At this point only the latter one can stub class methods on AVCaptureDeviceInput.
This problem is getting so common that I have decided to add a warning to OCMock. I'm thinking about the mock object printing a warning in cases where it has active stubs when it gets deactivated for class method stubbing. FWIW, there is some investigation under way to see whether it's possible to have more than one mock object mock class methods on the same class (https://github.com/erikdoe/ocmock/issues/173), but that's not trivial.
In my daily unit test coding with Xcode, I only use XCTestCase. There are also these other classes that don't seem to get used much such as: XCTestSuite, XCTest, XCTestRun.
What are XCTestSuite, XCTest, XCTestRun for? When do you use them?
Also, XCTestCase header has a few methods such as:
defaultTestSuite
invokeTest
testCaseWithInvocation:
testCaseWithSelector:
How and when to use the above?
I am having trouble finding documentation on the above XCTest-classes and methods.
Well, this question is pretty good and I just wondering why this question is being ignored.
As the document saying:
XCTestCase is a concrete subclass of XCTest that should be the override point for
most developers creating tests for their projects. A test case subclass can have
multiple test methods and supports setup and tear down that executes for every test
method as well as class level setup and tear down.
On the other hand, this is what XCTestSuite defined:
A concrete subclass of XCTest, XCTestSuite is a collection of test cases. Alternatively, a test suite can extract the tests to be run automatically.
Well, with XCTestSuite, you can construct your own test suite for specific subset of test cases, instead of the default suite ( [XCTestCase defaultTestSuite] ), which as all test cases.
Actually, the default XCTestSuite is composed of every test case found in the runtime environment - all methods with no parameters, returning no value, and prefixed with ‘test’ in all subclasses of XCTestCase.
What about the XCTestRun class?
A test run collects information about the execution of a test. Failures in explicit
test assertions are classified as "expected", while failures from unrelated or
uncaught exceptions are classified as "unexpected".
With XCTestRun, you can record information likes startDate, totalDuration, failureCount etc when the test is starting, or somethings like hasSucceeded when done, and therefore you got the result of running a test. XCTestRun gives you controlability to focus what is happening or happened about the test.
Back to XCTestCase, you will notice that there are methods named testCaseWithInvocation: and testCaseWithSelector: if you read source code. And I recommend you to do for more digging.
How do they work together ?
I've found that there is an awesome explanation in Quick's QuickSpec source file.
XCTest automatically compiles a list of XCTestCase subclasses included
in the test target. It iterates over each class in that list, and creates
a new instance of that class for each test method. It then creates an
"invocation" to execute that test method. The invocation is an instance of
NSInvocation, which represents a single message send in Objective-C.
The invocation is set on the XCTestCase instance, and the test is run.
Some links:
http://modocache.io/probing-sentestingkit
https://github.com/Quick/Quick/blob/master/Sources/Quick/QuickSpec.swift
https://developer.apple.com/reference/xctest/xctest?language=objc
Launch your Xcode, and use cmd + shift + O to open the quickly open dialog, just type 'XCTest' and you will find some related files, such as XCTest.h, XCTestCase.h ... You need to go inside this file to check out the interfaces they offer.
There is a good website about XCTest: http://iosunittesting.com/xctest-assertions/
I am Unit Testing MVVM based application that uses prism and using mocking to test view model . I am able to call the constructor of my viewmodel class by passing mock objects of region manager and resource manager but when control goes inside constructor it fails at the following statement :
private EventAggregator()
{
this.eventAggregatorInstance = ServiceLocator.Current.GetInstance<IEventAggregator>();
} It gives error : An unhandled exception of type 'Microsoft.Practices.ServiceLocation.ActivationException' occurred in Microsoft.Practices.ServiceLocation.dll
Additional information: Activation error occured while trying to get instance of type IEventAggregator, key "". Please help how to resolve this.
I see you solved your problem by adding the EventAggregator to your container.
However, I would suggest that your ViewModel should not be using the ServiceLocator to resolve the EventAggregator at all. The ServiceLocator is a glorified static instance that is basically an anti-pattern (see Service Locator is an Anti-Pattern). Your ViewModel should most likely accept the EventAggregator in the constructor via dependency injection and use it from there. I don't think you should need a container to test your ViewModels. You could just construct them with their constructors and pass them any mock implementations of their dependent objects (as parameters to the constructor).
Based on my understanding, the Service Locator gets initialized when running and initializing the Bootstrapper. Therefore, the exception you are issuing would be caused by not having the Locator initialized.
I believe the following post would be useful considering the non-Prism alternative taking into account that you didn't run the Bootstrapper on the Unit Test scope:
EventAggregator and ServiceLocator Issue
You would need to set the EventAggregator in the Mock Container, and then set the Service Locator service for that container:
(Quoted from above link)
IUnityContainer container = new UnityContainer();
// register the singleton of your event aggregator
container.RegisterType( new
ContainerControlledLifetimeManager() );
ServiceLocator.SetLocatorProvider( () => container );
I hope this helped you,
Regards.
In order to get code coverage report, i instrument the #Decorator bean by cobertura maven plugin.
When running my unit test in OpenEJB container. The container reports some error during start up (new initial context).
Caused by: org.apache.webbeans.exception.WebBeansConfigurationException: Decorator : MyDecorator, Name:null, WebBeans Type:DECORATOR, API Types:[org.apache.commo
ns.configuration.Configuration,net.sourceforge.cobertura.coveragedata.HasBeenInstrumented,org.apache.commons.configuration.AbstractConfiguration,MyDecorator,org.apache.commons.configuration.event.EventSource,java.lang.Object], Qualifiers:[javax.enterprise.inject.Any,javax.enterprise.inject.Default] delegate at
tribute must implement all of the decorator decorated types, but decorator type interface net.sourceforge.cobertura.coveragedata.HasBeenInstrumented is not assignable from deleg
ate type of interface org.apache.commons.configuration.Configuration
Details:
I have one Decorator to be unit tested.
Something like
import org.apache.commons.configuration.AbstractConfiguration;
import org.apache.commons.configuration.Configuration;
#Decorator
public class MyDecorator extends AbstractConfiguration {
#Inject
#Delegate
private Configuration conf;
.....
}
After cobertura instrumented it, the code is like below:(I uncompile it)
import net.sourceforge.cobertura.coveragedata.HasBeenInstrumented;
#Decorator
public class MyDecorator extends AbstractConfiguration
implements HasBeenInstrumented
{
#Inject
#Delegate
private Configuration conf;
.....
}
As you can see, cobertura add one more interface for my decorator.
When OpenEJB load and deploy this instrumented class, a error is reported:
Caused by: org.apache.webbeans.exception.WebBeansConfigurationException: Decorator : MyDecorator, Name:null, WebBeans Type:DECORATOR, API Types:[org.apache.commo
ns.configuration.Configuration,net.sourceforge.cobertura.coveragedata.HasBeenInstrumented,org.apache.commons.configuration.AbstractConfiguration,MyDecorator,org.apache.commons.configuration.event.EventSource,java.lang.Object], Qualifiers:[javax.enterprise.inject.Any,javax.enterprise.inject.Default] delegate at
tribute must implement all of the decorator decorated types, but decorator type interface net.sourceforge.cobertura.coveragedata.HasBeenInstrumented is not assignable from deleg
ate type of interface org.apache.commons.configuration.Configuration
The error log say that the #Decorator and the #Delegate should implement the same types.
But after instrument, the to be tested class has one more interface.
Then i try to instrument the org.apache.commons.configuration.AbstractConfiguration and org.apache.commons.configuration.Configuration. (by instrument the commons-configuration-1.9.jar by cobertura command line)
And modify my code like:
#Decorator
public class MyDecorator extends AbstractConfiguration {
#Inject
#Delegate
private AbstractConfiguration conf;
.....
}
//I use AbstractConfiguration instead of Configuration, because the Configuration is an //interface which could not be instrumented.
After all of this,the problem is solved.
But it is not a good way to do this.
The root cause is maven cobertura plugin identify the class file is instrumented by adding an interface to the original class, i works for most of the cases.
But not for a #Decorator bean which running in an container.
Should i create an comments for maven-cobertura-plugin org?
Any one has some suggestion on how to unit test #Decorators.And easy to get coverage report?
May be my unit test is not implement in the good way, maybe the openejb is not good for this?
Normally how do you unit test your #Decorators?
Cobertura does not instrument interfaces. It is recommended the non-instrumented classes go in the classpath after the instrumented classes for that reason.
So when instrumenting, compile first with maven normally, then place yourself in the directory where the sourcecode of the classes you want to instrument exists, and then run the following command : mvn cobertura:instrument.
This will make cobertura instrument all the classes, and maven will automatically add the files not instrumented. the instrumented code will be at ".\target\generated-classes\cobertura".
You'll need to run the 'jar -cvf [name-of-jar].jar *', then you'll get your instrumented jar.
I find it very odd that with such excellent Grails integration, Idea does not recognize standard JUnit assertion methods in Grails unit tests. I created a brand new project and made one domain class with corresponding test to make sure it wasn't something weird with my larger project. Even if I add a #Test annotation, the IDE does not see any assertion methods
#TestFor(SomeDomain)
class SomeDomainTests {
#Test //thought adding this, not needed for Grails tests, would help but it doesn't
void testSomething() {
assertEquals("something", 1, 1); //test runs fine, but IDE thinks this method and any similar ones don't exist
}
}
I have created an issue in IntelliJ bugtracker: http://youtrack.jetbrains.com/issue/IDEA-82790. It will be fixed in IDEA 11.1.0
As workaround you can add "import static org.junit.Assert.*" to imports.
Note: using "assert 1 == 1 : 'message'" is preferable than "assertEquals('message', 1, 1)" in groovy code.
Idea has problems if you use 'def' to define a variable (so it's type is not known) and then you try to pass it to a Java method which is strongly typed. Because it can't infer the type.
So it will give a message with words to the effect of "there is no method assertEquals() that takes arguments with type String, null, null".
I wouldn't expect this message in the example you give (because you are using ints directly, not a dynamically-typed variable) but I thought you might have missed it when trying to create a simple example code snippet for the question.
With the #TestFor annotation an AST will add methods to you test class and IDEA does not catch these methods.
You have two options:
Make the test class extends GrailsUnitTestCase.
Add dynamic method to your test class.