Unit Test for Private and Protected Methods with PHPUnit Magento 2.

PHPUnit used to test your code coverage. You can easily write a Public method test case with PHPUnit.

Writing Unit Test case for private and protected methods in PHP language can cause trouble due to you can’t call private and protected methods directly But they should be tested using a different approach.

Using the ReflectionMethod class invoke() method,
It’s possible to test both methods. In Magento Core code, few methods are tested with Private and Protected test case.

Example:
Core Sales Module contains a protected method,

File path: vendor/magento/module-sales/Block/Adminhtml/Order/Invoice/View.php

/**
 * Check whether order is under payment review
 *
 * @return bool
 */
protected function _isPaymentReview()
{
    $order = $this->getInvoice()->getOrder();
    return $order->canReviewPayment() || $order->canFetchPaymentReviewUpdate();
}

Check core Test file, vendor/magento/module-sales/Test/Unit/Block/Adminhtml/Order/Invoice/ViewTest.php

// Prepare block to test protected method
$expectedResult = true;
$block = $this->getMockBuilder(
    \Magento\Sales\Block\Adminhtml\Order\Invoice\View::class
)->disableOriginalConstructor()->setMethods(
    ['getInvoice']
)->getMock();
$block->expects($this->once())->method('getInvoice')->will($this->returnValue($invoice));

$testMethod = new \ReflectionMethod(
    \Magento\Sales\Block\Adminhtml\Order\Invoice\View::class,
    '_isPaymentReview'
);
$testMethod->setAccessible(true);

$this->assertEquals($expectedResult, $testMethod->invoke($block));

You can see we have created Mock for View.php file using $block.

Test Protected method, You need to call the ReflectionMethod class invoke method.

$testMethod = new \ReflectionMethod(
    \Magento\Sales\Block\Adminhtml\Order\Invoice\View::class,
    '_isPaymentReview'
);
$testMethod->setAccessible(true);
$this->assertEquals($expectedResult, $testMethod->invoke($block));

Defination:
ReflectionMethod(Original Class,Function from Original class)
Original Class: Magento\Sales\Block\Adminhtml\Order\Invoice\View.php
Function from Original class: protected _isPaymentReview

Now Using invoke method,$testMethod->invoke($block)
and check for equal assersion test.

Run Magento 2 Test using
php vendor/bin/phpunit -c dev/tests/unit/phpunit.xml.dist vendor/magento/module-sales/Test/Unit/Block/Adminhtml/Order/Invoice/ViewTest.php

Result will be success test.