PHPUnit testing a protected static method that uses pdo - pdo

I am very new to TDD. I am using phpunit 7.4x-dev. I have the following abstract class that I am trying to develop unit tests for.
use PDO;
abstract class Model {
protected static function getDB() {
static $db = null;
if ($db === null) {
$db = new PDO(ConfigDatabase::DSN, ConfigDatabase::USER, ConfigDatabase::PASSWORD);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
return $db;
}
}
I have created the following test to get around the need to deal with the static protected method. And it works if I provide "ConfigureDatabase" class.
use PHPUnit\Framework\TestCase;
class ModelTest extends TestCase {
function newMockClass(){
$stub = new class() extends Model{
function getStaticMethod($methodName){
return self::$methodName();
}
};
return $stub;
}
public function testDatabaseExists() {
$stub = $this->newMockClass();
$db = $stub->getStaticMethod('getDB');
$this->assertInstanceOf(PDO::class,$db);
}
}
Since I do not want my tests to rely on any actual database, How would I fake the calls to PDO.

Following Dormilich suggestion I developed a database interface, just in case I decide later I do not want to use PDO.
interface CRUDImp {
function __construct($datbaseBridgeLikePDO);
...
}
Next I wrote my tests for the constructor. I used setup to make sure I was starting with a fresh mock of \PDO.
class PDOWrapperTest extends TestCase {
private $pdoMock;
private $db;
function setup() {
$this->pdoMock = $this->createMock('\PDO');
$this->db = new PDOWrapper($this->pdoMock);
}
public function testWrapperExists() {
$this->pdoMock->method('getAttribute')->willReturn(\PDO::ERRMODE_EXCEPTION);
$db = new PDOWrapper($this->pdoMock);
$x = $db instanceof CRUDImp;
$this->assertTrue($x);
}
/**
* #expectedException \Exception
*/
public function testNonPDOPassedToConstructor() {
$mock = $this->createMock('\Exception');
$x = new PDOWrapper($mock);
}
...
}
Since PHP is loosely typed I check to make sure that the class passed to the constructor was an instance of \PDO. I implemented the concrete class as follows
class PDOWrapper implements CRUDImp {
private $pdo;
private $dataOutputType = \PDO::FETCH_ASSOC;
public function __construct($pdo) {
if (!($pdo instanceof \PDO)) {
throw new \Exception("PDOWrapper must be passed instance of \PDO");
}
$attr_Errmode = $pdo->getAttribute(\PDO::ATTR_ERRMODE);
if ($attr_Errmode !== \PDO::ERRMODE_EXCEPTION) {
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
}
$this->pdo = $pdo;
}
...
}
Now that I have an independent database wrapper the original Model tests are at the moment trivial and no longer needed. The abstract class Model was modified as follows:
abstract class Model {
protected $database=null;
function __construct(CRUDWrapper $database) {
$this->database = $database;
}
...
}
So for those not familiar with dependency injection I found the following links helpful:
http://php-di.org/doc/understanding-di.html
https://codeinphp.github.io/post/dependency-injection-in-php/
https://designpatternsphp.readthedocs.io/en/latest/Structural/DependencyInjection/README.html
Hope this shortens someone's work.

Related

Polymorphism on a REST service

I am trying to clean and refactor my service code which currently looks like this-
public void generateBalance(Receipt receipt) {
if (receipt.getType().equals(X) && receipt.getRegion.equals(EMEA)) {
// do something to the receipt that's passed
} else if (receiptType.equals(Y)) {
// do something to the receipt
} else if (receipt.getRegion.equals(APAC) {
// call an external API and update the receipt
}....
...
// finally
dataStore.save(receipt);
Basically there's a bunch of conditionals that are in this main service which look for certain fields in the object that is being passed. Either it's the type or the region.
I was looking to use this design pattern- https://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html
However, I am not sure how this would work for a service class. Currently my REST handler calls this particular service. Also how can I do polymorphism for both the "receiptType" and "region"?
Is there a way I can just do all the updates to the receipt once in different services, then finally save the receipt at one location? (maybe a base class?) I am really confused on how to start. TIA!
If your classes should have the same behaviour, then it becomes pretty simple to use polymorpism. The pattern is called as Strategy. Let me show an example.
At first we need to use enum. If you do not have enum, then you can create a method which will return enum value based on your conditions:
if (receipt.getType().equals(X) && receipt.getRegion.equals(EMEA)) // other
// code is omitted for the brevity
So enum will look like this:
public enum ReceiptType
{
Emea, Y, Apac
}
Then we need an abstract class which will describe behaviour for derived classes:
public abstract class ActionReceipt
{
public abstract string Do();
}
And our derived classes will look this:
public class ActionReceiptEmea : ActionReceipt
{
public override string Do()
{
return "I am Emea";
}
}
public class ActionReceiptY : ActionReceipt
{
public override string Do()
{
return "I am Y";
}
}
public class ActionReceiptApac : ActionReceipt
{
public override string Do()
{
return "I am Apac";
}
}
Moreover, we need a factory which will create derived classes based on enum. So we can use Factory pattern with a slight modification:
public class ActionReceiptFactory
{
private Dictionary<ReceiptType, ActionReceipt> _actionReceiptByType =
new Dictionary<ReceiptType, ActionReceipt>
{
{
ReceiptType.Apac, new ActionReceiptApac()
},
{
ReceiptType.Emea, new ActionReceiptEmea()
},
{
ReceiptType.Y, new ActionReceiptY()
}
};
public ActionReceipt GetInstanceByReceiptType(ReceiptType receiptType) =>
_actionReceiptByType[receiptType];
}
And then polymorpism in action will look like this:
void DoSomething(ReceiptType receiptType)
{
ActionReceiptFactory actionReceiptFactory = new ActionReceiptFactory();
ActionReceipt receipt =
actionReceiptFactory.GetInstanceByReceiptType(receiptType);
string someDoing = receipt.Do(); // Output: "I am Emea"
}
UPDATE:
You can create some helper method which will return enum value based on
your logic of region and receiptType:
public class ReceiptTypeHelper
{
public ReceiptType Get(ActionReceipt actionReceipt)
{
if (actionReceipt.GetType().Equals("Emea"))
return ReceiptType.Emea;
else if (actionReceipt.GetType().Equals("Y"))
return ReceiptType.Y;
return ReceiptType.Apac;
}
}
and you can call it like this:
void DoSomething()
{
ReceiptTypeHelper receiptTypeHelper = new ReceiptTypeHelper();
ReceiptType receiptType = receiptTypeHelper
.Get(new ActionReceiptEmea());
ActionReceiptFactory actionReceiptFactory = new
ActionReceiptFactory();
ActionReceipt receipt =
actionReceiptFactory.GetInstanceByReceiptType(receiptType);
string someDoing = receipt.Do(); // Output: "I am Emea"
}

JUnit5 - how to pass input collection to ParameterizedTest

I'm trying to translate a ParameterizedTest from JUnit4 to JUnit5 (sadly I'm not particularly skilled in testing).
In JUnit4 I have the following class:
#RunWith(Parameterized.class)
public class AssertionTestCase {
private final TestInput testInput;
public AssertionTestCase(TestInput testInput) {
this.testInput = testInput;
}
#Parameterized.Parameters
public static Collection<Object[]> data() {
return AssertionTestCaseDataProvider.createDataCase();
}
#Test(timeout = 15 * 60 * 1000L)
public void testDailyAssertion() {
LOG.info("Testing input {}/{}", testInput.getTestCase(), testInput.getTestName());
//assert stuffs
}
}
in the AssertionTestCaseDataProvider class I have a simple method generating a collection of Object[]:
class AssertionTestCaseDataProvider {
static Collection<Object[]> createDataCase() {
final List<TestInput> testInputs = new ArrayList<>();
//create and populate testInputs
return testInputs.stream()
.map(testInput -> new Object[]{testInput})
.collect(Collectors.toList());
}
}
I've been trying to translate it using JUnit5 and obtained this:
class AssertionTestCase {
private final TestInput testInput;
public AssertionTestCase(TestInput testInput) {
this.testInput = testInput;
}
public static Collection<Object[]> data() {
return AssertionTestCaseDataProvider.createDataCase();
}
#ParameterizedTest
#MethodSource("data")
void testDailyAssertion() {
LOG.info("Testing input {}/{}", testInput.getTestCase(), testInput.getTestName());
// assert stuffs
}
}
I did not apply any change to the AssertionTestCaseDataProvider class.
Nevertheless, I'm getting the following error:
No ParameterResolver registered for parameter [com.xxx.xx.xxx.xxx.testinput.TestInput arg0] in constructor [public `com.xxx.xxx.xxx.xxx.xxx.AssertionTestCase(com.xxx.xxx.xxx.xxx.testinput.TestInput)]. org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter [com.xxx.xx.xxx.xxx.testinput.TestInput arg0] in constructor [public com.xxx.xxx.xxx.xxx.xxx.AssertionTestCase(com.xxx.xxx.xxx.xxx.testinput.TestInput)].`
I understand I'm probably not applying correctly JUnit5 when initializing the input collection for the test. Am I missing some annotations?
I've also tried to use #ArgumentSource instead of #MethodSource and implementing Argument for AssertionTestCaseDataProvider, with the same failing results.
It works in a bit another way in Junit5.
Test Method should have parameters, and provider method should return a Stream.
static Stream<Arguments> data(){
return Stream.of(
Arguments.of("a", 1),
Arguments.of("d", 2)
);
}
#ParameterizedTest
#MethodSource("data")
void testDailyAssertion(String a, int b) {
Assertions.assertAll(
() -> Assertions.assertEquals("a", a),
() -> Assertions.assertEquals(1, b)
);
}
In your case you can just return a Stream<TestInput>:
static Stream<TestInput> createDataCase() {
final List<TestInput> testInputs = new ArrayList<>();
//create and populate testInputs
return testInputs.stream();
}
and then in your testMethod:
#ParameterizedTest
#MethodSource("createDataCase")
void testDailyAssertion(TestInput testInput) {
{your assertions}
}

Difference Stub Fixture

I am learning codeception and I wonder what is the difference between stubs and fixtures.
Both help me to load well-defined data and kepp tessts simple.
But when do I use
\Codeception\Util\Stub and when do I use
\Codeception\Util\Fixtures
So a stub is what Codeception uses to mock objects. In short, mocking is creating objects that simulate the behaviour of real objects.
Here is an example:
class UpdateBalance
{
public $balanceRepository;
public function __construct(BalanceRepositoryInterface $balanceRepository)
{
$this->balanceRepository = $balanceRepository;
}
public function subtract($amount, $id)
{
$updatedAmount = $this->balanceRepository->subtract($amount, $id);
if ($updatedAmount < 0) {
throw NegativeBalanceException($updatedAmount, $id);
}
return $updatedAmount;
}
}
class UpateBalanceTest extends PHPUnit_Framework_TestCase
{
public function testSubtractThrowsNegativeBalanceException()
{
$balanceRepository = Stub::make(
'BalanceRepositoryInterface'
array(
'subtract' => Stub::atLeastOnce(function() { return -100 })
)
);
$updateBalance = new UpdateBalance($balanceRepository);
$this->expectException(NegativeBalanceException::class);
$updateBalance->subtract(100, 1);
}
}
Note that we don't have a BalanceRepsository class. We have used Codeception stubs and pretended that the BalanceRepository class exists. By pretending it exists we can test the functionality of the UpdateBalance::subtract function by checking that the NegativeBalanceException is thrown.
Fixtures on the other hand would be for sharing test data throughout all your tests. If we use the UpdateBalance::subtract() example again, we could stress test the amount field ensuring it throws the correct exception depending on the amount being passed through:
// In some bootstrap or setup function
Fixtures::add('zero-amount', 0);
Fixtures::add('negative-amount', -1);
Fixtures::add('string-negative-amount', '-1');
class UpdateBalance
{
// ...
public function subtract($amount, $id)
{
if ($amount < 0) {
throw new
}
// ...
}
}
class UpateBalanceTest extends PHPUnit_Framework_TestCase
{
// ...
public function testSubtractThrowsCantSubtractNegativeAmountException()
{
$balanceRepository = Stub::make(
'BalanceRepositoryInterface'
);
$updateBalance = new UpdateBalance($balanceRepository);
$this->expectException(CantSubtractNegativeAmountException::class);
$updateBalance->subtract(Fixture::get('negative-amount'), 1);
}
}
Now we can use our pre-defined fixtures throughout all our tests. I would like to point out that using fixtures in the above example would probably be overkill, but for more complex test data like checking hexadecimal values are valid then it would be a lot more useful.

Using factory pattern for various components/modules

Let's say we have a system that builds articles. The article has some components validator, cleaner, storage.... In the client to build an article I have to instantiate each component:
$title = 'title';
$description = 'Description in html';
//Cleaner just clean some things from each field.
$cleaner = new Cleaner();
//Validator throw exception if something is not correct
$validator = new Validator();
// Storage save files and article itself
$storage = new Storage();
//Dom Class get some files from description field
$dom = new Dom();
$files = $dom->getFiles($description);
$storage->files($files);
$article = new ArticleBuilder();
$article->addTitle($validator->title($cleaner->title($title)));
$article->addDescription($validator->description($cleaner->description($description)));
$article->add....
Without these it's impossible to build an article.
My question is:
Can I use the factory pattern to create all of these like this:
class ArticleFactory
{
private $article;
public function __construct()
{
$this->article = new ArticleBuilder();
}
public function setTitle(string $title)
{
$title = ($this->validator())->title($title);
$title = ($this->cleaner())->title($title);
$this->article->addTitle($title);
}
public function setDescription(string $des)
{
$des = ($this->validator())->title($des);
$des = ($this->cleaner())->title($des);
$this->article->addDescription($des);
}
public function getArticle(): ArticleBuilder
{
return $this->article;
}
public function getFiles($description)
{
return ($this->dom())->getFiles($description);
}
public function storeFile($files)
{
($this->storage())->files($files);
}
public function validator(): ValidatorInterface
{
return new Validator();
}
public function cleaner(): CleanerInterface
{
return new Cleaner();
}
public function storage(): StorageInterface
{
return new Storage();
}
public function dom(): DomInterface
{
return new Dom();
}
}
In the client is more convenient to create an article with the above factory:
$myTitle = 'my title';
$myDes = 'mty description';
$article = new ArticleFactory();
$article->setTitle($myTitle);
$article->setDescription($myDes);
$files = $article->getFiles($description);
$article->storeFile($files);
Is this violates any of the SOLID principles?
Is there any better approach about this?
The class ArticleFactory seems to be violating SRP because ArticleFactory is concerned with more than one thing (building, storing, validating and cleaning articles).
There also seems to be a confusion here between the Factory pattern and the Builder pattern. If the class ArticleFactory also builds articles then it would be cleaner if it had (composition) a builder and delegated the building process to it. Do you really need a builder? Is the process of creating new articles so complicated/expensive that the builder pattern will add value?
The usage of nouns in the names of functions (function Validator, Cleaner, Storage) makes the code difficult to understand. What was your intention there?
Use verbs for functions and nouns for classes.

How to mock method call from other class in Rhino Mock AAA?

I have the following code(simplified).
public class OrderProcessor
{
public virtual string PlaceOrder(string test)
{
OrderParser orderParser = new OrderParser();
string tester = orderParser.ParseOrder(test);
return tester + " here" ;
}
}
public class OrderParser
{
public virtual string ParseOrder(string test)
{
if (!string.IsNullOrEmpty(test.Trim()))
{
if (test == "Test1")
return "Test1";
else
{
return "Hello";
}
}
else
return null;
}
}
My test is as follows -
public class OrderTest
{
public void TestParser()
{
// Arrange
var client = MockRepository.GenerateMock<OrderProcessor>();
var spec = MockRepository.GenerateStub<OrderParser>();
spec.Stub(x => x.ParseOrder("test")).IgnoreArguments().Return("Test1");
//How to pass spec to client so that it uses the same.
}
}
Now how do I test client so that it uses the mocked method from OrderParser.
I can mock the OrderParser but how do I pass that to the orderProcessor mocked class?
Please do let me know.
Thanks in advance.
I'm a little confused by your test since you are not really testing anything except that RhinoMocks works. You create two mocks and then do some assertions on them. You haven't even tested your real classes.
You need to do some dependency injection if you really want to get a good unit test. You can quickly refactor your code to use interfaces and dependency injection to make your test valid.
Start by extracting an interface from your OrderParser class:
public interface IOrderParser
{
String ParseOrder(String value);
}
Now make sure your OrderParser class implements that interface:
public class OrderParser: IOrderParser{ ... }
You can now refactor your OrderProcessor class to take in an instance of an IOrderParser object through its constructor. In this way you "inject" the dependency into the class.
public class OrderProcessor
{
IOrderParser _orderParser;
public OrderProcessor(IOrderParser orderParser)
{
_orderParser = orderParser;
}
public virtual string PlaceOrder(string val)
{
string tester = _orderParser.ParseOrder(val);
return tester + " here" ;
}
}
In your test you only want to mock out the dependency and not the SUT (Subject Under Test). Your test would look something like this:
public class OrderTest
{
public void TestParser()
{
// Arrange
var spec = MockRepository.GenerateMock<IOrderParser>();
var client = new OrderProcessor(spec);
spec.Stub(x => x.ParseOrder("test")).IgnoreArguments().Return("Test1");
//Act
var s = client.PlaceOrder("Blah");
//Assert
Assert.AreEqual("Test1 Here", s);
}
}
It is difficult for me to gauge what you are trying to do with your classes, but you should be able to get the idea from this. A few axioms to follow:
Use interfaces and composition over inheritance
Use dependency injection for external dependencies (inversion of control)
Test a single unit, and mock its dependencies
Only mock one level of dependencies. If you are testing class X which depends on Y which depends on Z, you should only be mocking Y and never Z.
Always test behavior and never implementation details
You seem to be on the right track, but need a little guidance. I would suggest reading material that Martin Fowler, and Bob Martin have to get up to speed.