Can't pass GET parameter while unit testing Zend Framework 2 - get

I'm having hard time trying to unit test (phpUnit) one of my modules in ZF2. What I'm trying to do is determine whether a classname is present on one of the elements on page when a GET parameter is passed to the controller.
It all works from the browser, however I can't get the GET parameter to be recognized at all when trying to unit test.
This is my code for unit testing:
<?php
namespace ComponentManager\Controller;
use Zend\Test\PHPUnit\Controller\AbstractHttpControllerTestCase;
class ComponentManagerControllerTest extends AbstractHttpControllerTestCase
{
public function setUp()
{
$this->setApplicationConfig(
include 'config/application.config.php'
);
parent::setUp();
}
public function testAdminComponentCodeCanBeAccessed()
{
$this->dispatch('/ComponentManager/requestComponent/product/details-1/details-1', 'GET', array('admin' => 1));
// I also tried: $this->dispatch('/ComponentManager/requestComponent/product/details-1/details-1?admin=1');
$this->assertResponseStatusCode(200);
$this->assertMatchedRouteName('ComponentManager/path');
$this->assertControllerName('ComponentManager\Controller\ComponentManager');
$this->assertControllerClass('ComponentManagerController');
$this->assertActionName('requestComponent');
$this->assertModuleName('ComponentManager');
// test will fail here
$this->assertQuery('div.config-active-wrapper');
}
}
The "div.config-active-wrapper" selector works fine when I remove the check for admin parameter presence in GET but when I re-add it, the GET parameter doesn't get recognised at all. Any ideas?

The problem here was that unit testing is a CLI operation and no superglobals are being populated while in CLI. Simple and stupid :P
A solution is to not use superglobals like $_GET here but to pass this "admin" parameter via some ACL and a controller instead.

Related

passing a parameter from a content type to a module

I assumed this would be easy but I am stumped.
I have a custom content type that includes an id field. I render these with a basic page template.
I have written a small module that creates a block which is populated with data from an external API. Everything works except I cannot seem to figure out how to pass the value of the id from the content of a given page to my module so it can make the API call.
It would be a couple of lines of code in straight php, it can't be that complicated in Drupal 8 and twig can it?
I managed to find a solution here
I am re-posting it in case it is useful to anyone else.
If you are generating a custom block you can access content fields via the routing system inside your block build function like this:
public function build() {
if ($node = \Drupal::routeMatch()->getParameter('node')) {
$field_my_custom_value = $node->field_my_custom_value->value;
}
//do something with the variable, like make the API call
//Make sure to set the cache to the context or even to zero if you need
return array(
'#markup' => $this->t('my content to render'),
'#cache' => array(
'contexts' => ['contexts' => ['route']],
),
);
}
I think you can reach what you want with a HOOK_preprocess.
use:
YOUR_MODULE_preprocess_node(&$variables){ ... } or
YOUR_MODULE_preprocess_block(&$variables){ ... }
to access your variable from the content type and pass it to your function oder template.

Mockito isNotNull passes null

Thanks in advance for the help -
I am new to mockito but have spent the last day looking at examples and the documentation but haven't been able to find a solution to my problem, so hopefully this is not too dumb of a question.
I want to verify that deleteLogs() calls deleteLog(Path) NUM_LOGS_TO_DELETE number of times, per path marked for delete. I don't care what the path is in the mock (since I don't want to go to the file system, cluster, etc. for the test) so I verify that deleteLog was called NUM_LOGS_TO_DELETE times with any non-null Path as a parameter. When I step through the execution however, deleteLog gets passed a null argument - this results in a NullPointerException (based on the behavior of the code I inherited).
Maybe I am doing something wrong, but verify and the use of isNotNull seems pretty straight forward...here is my code:
MonitoringController mockController = mock(MonitoringController.class);
// Call the function whose behavior I want to verify
mockController.deleteLogs();
// Verify that mockController called deleteLog the appropriate number of times
verify(mockController, Mockito.times(NUM_LOGS_TO_DELETE)).deleteLog(isNotNull(Path.class));
Thanks again
I've never used isNotNull for arguments so I can't really say what's going wrong with you code - I always use an ArgumentCaptor. Basically you tell it what type of arguments to look for, it captures them, and then after the call you can assert the values you were looking for. Give the below code a try:
ArgumentCaptor<Path> pathCaptor = ArgumentCaptor.forClass(Path.class);
verify(mockController, Mockito.times(NUM_LOGS_TO_DELETE)).deleteLog(pathCaptor.capture());
for (Path path : pathCaptor.getAllValues()) {
assertNotNull(path);
}
As it turns out, isNotNull is a method that returns null, and that's deliberate. Mockito matchers work via side effects, so it's more-or-less expected for all matchers to return dummy values like null or 0 and instead record their expectations on a stack within the Mockito framework.
The unexpected part of this is that your MonitoringController.deleteLog is actually calling your code, rather than calling Mockito's verification code. Typically this happens because deleteLog is final: Mockito works through subclasses (actually dynamic proxies), and because final prohibits subclassing, the compiler basically skips the virtual method lookup and inlines a call directly to the implementation instead of Mockito's mock. Double-check that methods you're trying to stub or verify are not final, because you're counting on them not behaving as final in your test.
It's almost never correct to call a method on a mock directly in your test; if this is a MonitoringControllerTest, you should be using a real MonitoringController and mocking its dependencies. I hope your mockController.deleteLogs() is just meant to stand in for your actual test code, where you exercise some other component that depends on and interacts with MonitoringController.
Most tests don't need mocking at all. Let's say you have this class:
class MonitoringController {
private List<Log> logs = new ArrayList<>();
public void deleteLogs() {
logs.clear();
}
public int getLogCount() {
return logs.size();
}
}
Then this would be a valid test that doesn't use Mockito:
#Test public void deleteLogsShouldReturnZeroLogCount() {
MonitoringController controllerUnderTest = new MonitoringController();
controllerUnderTest.logSomeStuff(); // presumably you've tested elsewhere
// that this works
controllerUnderTest.deleteLogs();
assertEquals(0, controllerUnderTest.getLogCount());
}
But your monitoring controller could also look like this:
class MonitoringController {
private final LogRepository logRepository;
public MonitoringController(LogRepository logRepository) {
// By passing in your dependency, you have made the creator of your class
// responsible. This is called "Inversion-of-Control" (IoC), and is a key
// tenet of dependency injection.
this.logRepository = logRepository;
}
public void deleteLogs() {
logRepository.delete(RecordMatcher.ALL);
}
public int getLogCount() {
return logRepository.count(RecordMatcher.ALL);
}
}
Suddenly it may not be so easy to test your code, because it doesn't keep state of its own. To use the same test as the above one, you would need a working LogRepository. You could write a FakeLogRepository that keeps things in memory, which is a great strategy, or you could use Mockito to make a mock for you:
#Test public void deleteLogsShouldCallRepositoryDelete() {
LogRepository mockLogRepository = Mockito.mock(LogRepository.class);
MonitoringController controllerUnderTest =
new MonitoringController(mockLogRepository);
controllerUnderTest.deleteLogs();
// Now you can check that your REAL MonitoringController calls
// the right method on your MOCK dependency.
Mockito.verify(mockLogRepository).delete(Mockito.eq(RecordMatcher.ALL));
}
This shows some of the benefits and limitations of Mockito:
You don't need the implementation to keep state any more. You don't even need getLogCount to exist.
You can also skip creating the logs, because you're testing the interaction, not the state.
You're more tightly-bound to the implementation of MonitoringController: You can't simply test that it's holding to its general contract.
Mockito can stub individual interactions, but getting them consistent is hard. If you want your LogRepository.count to return 2 until you call delete, then return 0, that would be difficult to express in Mockito. This is why it may make sense to write fake implementations to represent stateful objects and leave Mockito mocks for stateless service interfaces.

Check the url in a Geb/Spock test

In my Spock functional test, I want to test that the current location of the browser is not a certain url. I know I can do:
try {
at(PageWithUrlIDontWant)
// do something
} catch (AssertionError) {
// pass because this is the common branch
}
However, this is using exceptions to control branching. Is there a way, besides at, to check what url the browser is at? I have tried page.pageUrl and browser.pageUrl but they are both null.
As of Geb 0.7.0, there is a new isAt() method on the class Browser. GebSpec proxies methodMissing calls to it's Browser instance so this method is available in your test. This method returns true/false instead of throwing an exception and should be exposed.
Example:
def "navigating to GoodPage doesn't up at BadPage"() {
when:
to GoodPage
then:
!isAt(BadPage)
}

Unit test rest service without specifying URL

Using servicestack, there are examples of unit testing using types, etc. Here is an example:
GetFactorial
I would like to test my REST style service with a test similar to the above.
Here is an example REST unit test FileService
Notice how in the PUT unit test, the Path argument has to be specified in the URL text instead of in the class argument. Another example is here, where we have perfectly good request models that have to be translated into the URL. For testing, I would like to get away from having to build the arguments in the url and use a system similar to the one above like this:
var response = restClient.Put<FilesResponse>(new Files { TextContents = ReplacedFileContents, Path = "README.txt" });
or
var singleCustomer = restClient.Get<Customer>(new Customer {Id=1};
Is this possible?
Then there is the DirectServiceClient. Would that help? In the end, with servicestack, we get to write services and they can be called from many different type clients - I would like to write my unit test like that.
Is this possible?
If you decorate your DTOs with the route variable and use ServiceStack's "New API" then it can discover the routes automatically. You can get away with writing very minimal code and still get a strong typed rest API.
Your code could look something like this:
Customer singleCustomer = restClient.Get(new Customer {Id=1});
See https://github.com/ServiceStack/ServiceStack/wiki/New-Api
In response to your comments, your DTO needs to adhere to the IReturn interface:
[Route("/customer/{Id}")]
public Customer : IReturn<Customer> {
public int Id {get;set;}
}
The IRestClient interface below will now be able to work with your DTO without specify the type since it is expecting an IReturn object.
public interface IRestClient
{
TResponse Get<TResponse>(IReturn<TResponse> request);
...
}

Checking for an attribute on a destination property inside a custom AutoMapper TypeConverter

I have a custom type converter that converts UTC DateTime properties to a company's local time (talked about here: Globally apply value resolver with AutoMapper).
I'd now like to only have this converter do its thing if the property on the view model is tagged with a custom DisplayInLocalTime attribute.
Inside the type converter, if I implement the raw ITypeConvert<TSource, TDestination> interface, I can check if the destination view model property being converted has the attribute:
public class LocalizedDateTimeConverter : ITypeConverter<DateTime, DateTime>
{
public DateTime Convert(ResolutionContext context)
{
var shouldConvert = context.Parent.DestinationType
.GetProperty(context.MemberName)
.GetCustomAttributes(false)[0].GetType() == typeof(DisplayInLocalTimeAttribute);
if (shouldConvert) {
// rest of the conversion logic...
}
}
}
So this code works just fine (obviously there's more error checking and variables in there for readability).
My questions:
Is this the correct way to go about this? I haven't found anything Googling around or spelunking through the AutoMapper code base.
How would I unit test this? I can set the parent destination type on the ResolutionContext being passed in with a bit of funkiness, but can't set the member name as all implementors of IMemberAccessor are internal to AutoMapper. This, and the fact that it's super ugly to setup, makes me this isn't really supported or I'm going about it all wrong.
I'm using the latest TeamCity build of AutoMapper, BTW.
Don't unit test this, use an integration test. Just write a mapping test that actually calls AutoMapper, verifying that whatever use case this type converter is there to support works from the outside.
As a general rule, unit tests on extension points of someone else's API don't have as much value to me. Instead, I try to go through the front door and make sure that I've configured the extension point correctly as well.

Resources