I'm running into an issue when unit testing a controller. In attempting to test a request, the test incorrectly directs to the wrong method. Example below, which should clearly illustrate the problem.
Parent Controller
class ExampleParentController {
def someMethod = {
render "FALSE"
}
def someMethod(def object)
{
render "DEFINITELY FALSE"
}
}
Child Controller
class ExampleChildController extends ExampleParentController {
def someMethod = {
render "TRUE"
}
}
Test Class
class ExampleChildControllerTests extends ControllerUnitTestCase {
protected void setUp() {
super.setUp()
}
protected void tearDown() {
super.tearDown()
}
void testSomeMethod() {
controller.someMethod()
def result = controller.response.contentAsString
assertEquals ("TRUE", result)
}
}
I would expect that controller.someMethod() would render "TRUE". This works perfectly when executed while the application is running, as someMethod(def object) isn't exposed as an endpoint. Is there a way to specify which method to execute?
Related
I have the following classes shown below, legacy code. The goal I want to achieve is to ensure that the delegate method processUser is called with the user data passed. Second, I also want to ensure that the passed in Registration object's doRegister is called. My attemot is shown below for the delegate, but the test does not pass as it says, Too few invocations. I am using Groovy spock for testing version 1.2
class Invoker {
Delegate delegate;
Invoker(Delegate delegate) {
this.delegate = delegate;
}
void invoke(UserData user) {
delegate.processUser(user);
}
}
class Delegate {
private RegistrationService service;
Delegate (RegistrationService r) {
this.service = r;
}
void processUser(UserData data) {
service.doRegistration(data);
}
}
class DelegateSpec extends Specification {
Delegate delegate
RegistrationService registration
Invoker invoker
def setup() {
registration = Mock()
delegate = new Delegate(registration)
Invoker invoker = new Invoker(delegate)
}
def "Invoker should invoke delegate passed to it"() {
given:
UserData u = ....
when:
invoker.invoke(u)
then:
1* delegate.processUser(u)
}
}
First let me provide a fully consistent set of classes in order to be able to compile the application code:
package de.scrum_master.stackoverflow.q59366025;
public class UserData {}
package de.scrum_master.stackoverflow.q59366025;
public class RegistrationService {
public void doRegistration(UserData data) {}
}
package de.scrum_master.stackoverflow.q59366025;
class Delegate {
private RegistrationService service;
Delegate (RegistrationService r) {
this.service = r;
}
void processUser(UserData data) {
service.doRegistration(data);
}
}
package de.scrum_master.stackoverflow.q59366025;
class Invoker {
Delegate delegate;
Invoker(Delegate delegate) {
this.delegate = delegate;
}
void invoke(UserData user) {
delegate.processUser(user);
}
}
Now as for your test, you are making it more complicated than necessary and there is also a logical error:
If the Delegate is not mock or spy, you cannot check interactions like 1 * on it.
So just make it a mock, then you also do not need to inject its RegistrationService dependency anymore - which is the whole point of creating a mock.
package de.scrum_master.stackoverflow.q59366025
import spock.lang.Specification
class DelegateSpec extends Specification {
def delegate = Mock(Delegate)
def invoker = new Invoker(delegate)
def "Invoker should invoke delegate passed to it"() {
given:
def userData = new UserData()
when:
invoker.invoke(userData)
then:
1 * delegate.processUser(userData)
}
}
Is it possible to mock the
EntityRepository::findOneBy{$field}($value)
function?
Using:
->getMock('EntityRepository')
->expects($this->any())
->method('findOneByField')
resolves always in null, as findOneByField isn't a real function but gets mapped by __call(). At least I think that that is the problem..
You can mock the __call method. Will give a simple example:
Class:
class A {
public function __call($fname, $args) {
if($fname === 'test') {
return 'test';
}
}
}
Test:
class ATest extends PHPUnit_Framework_TestCase
{
public function testA() {:
$mock = $this->getMock('A');
$mock->expects($this->any())
->method('__call')
->with('test')
->will($this->returnValue('test'));
var_dump($mock->test());
}
}
You can do the same with the EntityRepository. I just hadn't one by the hand for testing.
I'm trying to mock a service in an integration test for a dynamically scaffolded controller. I get an error indicating that the controller property for the service is not accessible from the test.
It seems that dynamically scaffolded controllers can't be tested with unit tests at all so I'm using integration tests. I want to mock the service to test error handling in my app. Is this a bug in Grails 2.2.0 or am I just doing it wrong?
The result for grails test-app is:
groovy.lang.MissingPropertyException: No such property: myService for class: MyController
Example:
I have modified the src/templates/scaffolding/Controller.groovy:
class ${className}Controller {
MyService myService
def action() {
render myService.serviceMethod()
}
}
Dynamically scaffolded MyController.groovy:
class MyController {
static scaffold = MyDomainClass
}
Integration test MyControllerTests.groovy:
class MyControllerTests extends GroovyTestCase {
def myController
#Before
void setUp() {
myController = new MyController()
}
void testMock() {
myController.myService = [ serviceMethod : { return "foo" } ] as MyService
controller.action()
}
}
Try using the setter method:
void testMock() {
myController.setMyService([ serviceMethod : { return "foo" } ])
controller.action()
}
If you execute: println c.metaClass.methods*.name, you will see that there are methods like getSetMyService() and getGetMyService(). I'm not sure of it, but probably Grails is not adding fields but instead getters for field get/set methods.
The integration test should be implemented as shown below. If we mock the service in a test we must reset it ourselves. Grails does not do it for us which is mysterious because the controller is created in setUp().
droggo's answer above reveals the correct way to inject the mock in the SUT. I'll also add an example of using a Groovy mock. It's bit more verbose though.
class MyControllerTests extends GroovyTestCase {
def myController
def myService
#Before
void setUp() {
myController = new MyController()
}
#After
void tearDown() {
myController.setMyService(myService)
}
void testMapMock() {
myController.setMyService([ serviceMethod : { return "foo" } ] as MyService)
controller.action()
}
void testGroovyMock() {
def myServiceMockContext = new StubFor(MyService)
myServiceMockContext.demand.serviceMethod() { -> return "bar" }
def myService = myServiceMockContext.proxyInstance()
controller.setMyService(myService)
controller.action()
}
}
given a domain constellation like this:
abstract class A {
def myService
def beforeInsert() {
myService.doIt()
}
}
class B extends A {
def beforeInsert() {
super.beforeInsert()
}
}
Is it possible to mock the following methods:
- beforeInsert() in B?
- beforeInsert() in A?
For making service method calls optional for unit testing the easiest thing to do is to use null safe method calls:
abstract class A {
def myService
static transients = ['myService']
def beforeInsert() {
myService?.doIt()
}
}
class B extends A {
def beforeInsert() {
super.beforeInsert()
}
}
Save B objects without flushing in unit tests or
override beforeInsert by metaClass:
B.metaClass.beforeInsert = {-> }
Is there a way to do a conditional TearDown in NUnit?
I have a TestFixture which has a need to run cleanup code for just a few tests, and I don't really want to:
Run the TearDown method on every test
Create a private helper method and call it from the tests requiring cleanup if I can avoid it
There isn't unfortunately.
Can you not do the cleanup in the [TestFixtureTearDown] instead, so once all the tests have finished? I guess that depends on whether the cleanup has to be done before the next test runs.
Alternatively, put those tests that require a cleanup in another class/TextFixture together, away from the other tests. Then you can use a TearDown in there which doesn't need to be conditional.
Edit:
One thing I've just thought of, which could be done to achieve the aim though probably isn't actually worth it for this particular need, is that you can extend NUnit - create your own custom attributes which you could handle however you wanted. This is mentioned here. Like I say, I don't think really you should go down that route for this, but is useful to know none-the-less
You can have the main TearDown in a base class:
[TearDown]
public virtual void TearDown()
{
// Tear down things here
}
and then override it in the class where you have the tests that should not run the tear down code:
[TearDown]
public override void TearDown()
{
// By not calling base.TearDown() here you avoid tearing down
}
Extend all you classes with test from BaseTest
public class BaseTest
{
[SetUp]
public void BeforeTest()
{
GetService<NUnitHooksController>().ExecuteBeforeTestHooks(this);
}
[TearDown]
public void AfterTest()
{
GetService<NUnitHooksController>().ExecuteAfterTestHooks(this);
}
}
Use AfterTest and BeforeTest hooks. Works both with and without category.
public class ExampleTest : BaseTest
{
[Test, Category("asdasd")]
public void Test01()
{
...
}
[AfterTest("asdasd")]
public void ExampleHook()
{
...
}
}
public class NUnitHooksController
{
private readonly ILogger _log;
public NUnitHooksController(ILogger log)
{
_log = log;
}
public void ExecuteBeforeTestHooks(object testClass)
{
ExecuteHooks(testClass, typeof(BeforeTestAttribute));
}
public void ExecuteAfterTestHooks(object testClass)
{
ExecuteHooks(testClass, typeof(AfterTestAttribute));
}
private MethodInfo[] GetHookMethods(object currentTestClass, Type attributeType)
{
return currentTestClass
.GetType()
.GetMethods()
.Where(m => m.GetCustomAttributes(attributeType, false).Length > 0)
.ToArray();
}
private void ExecuteHooks(object testClass, Type requiredAttributeType)
{
var hooks = GetHookMethods(testClass, requiredAttributeType);
var testCategories = GetTestCategories();
foreach (var hook in hooks)
{
var allAttributes = hook.GetCustomAttributes(requiredAttributeType, true);
foreach (var attribute in allAttributes)
{
if (!attribute.GetType().IsEquivalentTo(requiredAttributeType))
{
continue;
}
var hookCategories = GetCategoriesFromAttribute(attribute);
// if we do not have specific category on hook
// or we have at least one same category on hook and test
if (!hookCategories.Any() || hookCategories.Intersect(testCategories).Any())
{
ExecuteHookMethod(testClass, hook);
}
}
}
}
private object[] GetTestCategories()
{
return TestContext.CurrentContext.Test.Properties["Category"].ToArray();
}
private void ExecuteHookMethod(object testClass, MethodInfo method)
{
var hookName = method.Name;
_log.Information($"Executing - '{hookName}' hook");
try
{
method.Invoke(testClass, Array.Empty<object>());
}
catch (Exception e)
{
_log.Error($"Executing of - '{hookName}' hook failed - {e}");
}
}
private string[] GetCategoriesFromAttribute(object attribute)
{
if (attribute is BeforeTestAttribute beforeTestAttribute)
{
return beforeTestAttribute.Categories;
}
if (attribute is AfterTestAttribute afterTestAttribute)
{
return afterTestAttribute.Categories;
}
throw new ArgumentException($"{attribute.GetType().FullName} - does not have categories");
}
}
I have solved this using the name of the test:
namespace TestProject
{
public class TestClass
{
// Test without TearDown
[Test]
public void Test1()
{
Assert.Pass("Test1 passed");
}
// Test with TearDown
[Test]
public void Test2()
{
Assert.Pass("Test2 passed");
}
[TearDown]
public void TearDown()
{
// Execute only after Test2
if (TestContext.CurrentContext.Test.Name.Equals(nameof(this.Test2)))
{
// Execute Test2 TearDown...
}
}
}
}
Or if you want to use the full name of Test2 (TestProject.TestClass.Test2) you can replace the line
if (TestContext.CurrentContext.Test.Name.Equals(nameof(this.Test2)))
by
if (TestContext.CurrentContext.Test.FullName.Equals(typeof(TestClass).FullName + "." nameof(this.Test2)))