patternphpMinor
Unit-testing ExtFilterParser Symfony2 service
Viewed 0 times
symfony2extfilterparserservicetestingunit
Problem
The Service:
```
filters;
}
public function getParsedFilters() {
return $this->parsedFilters;
}
public function getFilters() {
return $this->filters;
}
public function setFilters($filters) {
$this->filters = $filters;
return $this;
}
public function __construct(\Symfony\Component\HttpFoundation\Request $request) {
$this->filters = $this->pullFilterJsonFromRequest($request);
}
private function pullFilterJsonFromRequest($request) {
$filterJson = '';
$filterFromGet = $request->query->get($this->requestParam);
$filterFromPost = $request->request->get($this->requestParam);
if(empty($filterFromGet) === FALSE) {
$filterJson = $filterFromGet;
} elseif(empty($filterFromPost) === FALSE) {
$filterJson = $filterFromPost;
}
return $filterJson;
}
public function parse() {
$decodedFilters = $this->decodeFilterJson($this->filters);
foreach($decodedFilters as $filter) {
switch($filter->type) {
case 'numeric':
$this->parsedFilters[] = $this->parseComparisonFilter($filter);
break;
case 'date':
$this->parsedFilters[] = $this->parseDateFilter($filter);
break;
case 'list':
$this->parsedFilters[] = $this->parseListFilter($filter);
break;
case 'string':
$this->parsedFilters[] = $this->parseStringFilter($filter);
break;
default:
throw new \UnexpectedValueException(__METHOD__ . " Unknown filter type '$filter->type'");
}
}
return $this;
}
public function parseIntoQueryBuilder(\Doctrine\ORM\QueryBuilder $queryBuilder) {
$this->parse();
foreach($this->parsedFilters as $filter) {
```
filters;
}
public function getParsedFilters() {
return $this->parsedFilters;
}
public function getFilters() {
return $this->filters;
}
public function setFilters($filters) {
$this->filters = $filters;
return $this;
}
public function __construct(\Symfony\Component\HttpFoundation\Request $request) {
$this->filters = $this->pullFilterJsonFromRequest($request);
}
private function pullFilterJsonFromRequest($request) {
$filterJson = '';
$filterFromGet = $request->query->get($this->requestParam);
$filterFromPost = $request->request->get($this->requestParam);
if(empty($filterFromGet) === FALSE) {
$filterJson = $filterFromGet;
} elseif(empty($filterFromPost) === FALSE) {
$filterJson = $filterFromPost;
}
return $filterJson;
}
public function parse() {
$decodedFilters = $this->decodeFilterJson($this->filters);
foreach($decodedFilters as $filter) {
switch($filter->type) {
case 'numeric':
$this->parsedFilters[] = $this->parseComparisonFilter($filter);
break;
case 'date':
$this->parsedFilters[] = $this->parseDateFilter($filter);
break;
case 'list':
$this->parsedFilters[] = $this->parseListFilter($filter);
break;
case 'string':
$this->parsedFilters[] = $this->parseStringFilter($filter);
break;
default:
throw new \UnexpectedValueException(__METHOD__ . " Unknown filter type '$filter->type'");
}
}
return $this;
}
public function parseIntoQueryBuilder(\Doctrine\ORM\QueryBuilder $queryBuilder) {
$this->parse();
foreach($this->parsedFilters as $filter) {
Solution
The concerns you have raised are valid. This test is currently relying on the Request object (and is testing that object where it shouldn't be).
You have written the code well, injecting the dependency for the Request object into the constructor. This gives you the seam required for testing (Misko Hevery talks about seams and gives awesome advice on testing in many other places).
In your test you can make your seam by using mocked objects. What you really want to test is that the mock (a friendly object that you control with your test code) receives the expected stimuli. This means that you should be testing that your Request object is used correctly by your service code. You also define what you want your mock to return to your service code so that you are able to ensure that your service code reacts to the stimuli received from your Request.
PHPUnit makes it easy for you to create Mock objects. The whole of Chapter 10 is a good read.
The good news is that you only have tight coupling in your test code. Using the mock objects will remove this for you fairly easily.
You have written the code well, injecting the dependency for the Request object into the constructor. This gives you the seam required for testing (Misko Hevery talks about seams and gives awesome advice on testing in many other places).
In your test you can make your seam by using mocked objects. What you really want to test is that the mock (a friendly object that you control with your test code) receives the expected stimuli. This means that you should be testing that your Request object is used correctly by your service code. You also define what you want your mock to return to your service code so that you are able to ensure that your service code reacts to the stimuli received from your Request.
PHPUnit makes it easy for you to create Mock objects. The whole of Chapter 10 is a good read.
The good news is that you only have tight coupling in your test code. Using the mock objects will remove this for you fairly easily.
Context
StackExchange Code Review Q#9191, answer score: 2
Revisions (0)
No revisions yet.