PHPUnit fails testing a custom exception - unit-testing

I am having trouble to test correctly a thrown exception (Is it a namspacing problem).
Here is my custom exception:
<?php
namespace Example\Customexception;
class ResourceNotAvailableException extends \Exception {}
Here the class I am testing:
namespace Example\Lib;
use Example\Customexception\ResourceNotAvailableException;
class Configuration {
private static $instance;
private $arrConfig;
private function __construct($configFile)
{
$this->arrConfig = parse_ini_file($configFile, true);
if ($this->arrConfig == false){
throw new ResourceNotAvailableException("Config file {$configFile} not available.");
}
}
public static function getInstance($configFile = "config/config.ini")
{
if (self::$instance == null){
try {
self::$instance = new Configuration($configFile);
}
catch(ResourceNotAvailableException $e) {
throw $e;
}
}
return self::$instance;
}
}
And here is my test class:
use Example\Lib\Configuration;
class ConfigurationTest extends PHPUnit_Framework_TestCase {
/**
* #expectedException Example\Customexception\ResourceNotAvailableException
*/
function testGetInstanceThrowsException()
{
$configuration = Configuration::getInstance("configtestini");
}
}
And here is the output I get:
PHPUnit 5.3.2 by Sebastian Bergmann and contributors.
E 1 / 1 (100%)
Time: 89 ms, Memory: 2.75Mb
There was 1 error:
1) ConfigurationTest::testGetInstanceThrowsException
parse_ini_file(configtestini): failed to open stream: No such file or directory
/home/me/workspace/codeexample/src/Lib/Configuration.php:24
/home/me/workspace/codeexample/src/Lib/Configuration.php:39
/home/me/workspace/codeexample/tests/unit/Lib/ConfigurationTest.php:14
FAILURES!
Tests: 1, Assertions: 0, Errors: 1.
Please ignore the line numbers in the output because I removed some comments from the code to make it easily readable here.
Thanks

parse_ini_file() raises an error which is turned into an exception by PHPUnit's error handler.

Related

How can I prevent a method call when JUnit testing with Mockito?

For the life of me, I can't seem to figure out how to prevent the method I'm testing from calling a method in another class.
Here is my test class:
#ExtendWith(MockitoExtension.class)
class QueryHandlerTest {
#InjectMocks
QueryHandler queryHandler;
#Mock
ResponseBuilder responseBuilder;
#BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}
#Test
void TC5() {
doThrow(AddMessageResponseException.class).when(responseBuilder).addMessageResponse(isA(Boolean.class), isA(Boolean.class));
assertThrows(AddMessageResponseException.class, ()-> queryHandler.addMessage("Hello",true));
}
}
Here is the method that I'm testing:
public void addMessage(String message, boolean lengthExceedsLimit) {
boolean messageAdded;
if (checkIfJarExists()) {
if (!lengthExceedsLimit) {
// attempt to add the message to the jar
messageAdded = addMessageQuery(new Message(event.getMessageAuthor().getIdAsString(), message));
} else {
messageAdded = false;
}
} else {
messageAdded = false;
}
responseBuilder.addMessageResponse(messageAdded, lengthExceedsLimit);
if (messageAdded) {
// check to see if the jar's message limit has been reached; if so, perform opening ceremony
if (checkMessageLimit()) {
responseBuilder.performOpeningEvent(currentJar);
deleteJarQuery(this.serverId);
}
}
}
And here is the method that it's calling:
public void addMessageResponse(boolean messageAdded, boolean lengthExceedsLimit){
if (lengthExceedsLimit) {
event.getChannel().sendMessage("I'm sorry, your message is too long. Please limit your message " +
"to 250 characters or less.");
} else if(messageAdded){
String nickname = getNickname();
event.getChannel().sendMessage("Thanks, " + nickname + "! Your message has " +
"been added to the jar!");
} else {
event.getChannel().sendMessage("Sorry, it looks like a jar has not been set up for your server. " +
"If you're a server admin, you can create a jar! " +
"Please use '!tiko help' to see a list of my commands.");
}
}
When I run the test, I get this output:
org.opentest4j.AssertionFailedError: Unexpected exception type thrown,
Expected :class com.tikoJar.exceptions.AddMessageResponseException
Actual :class java.lang.NullPointerException
<Click to see difference>
...
Caused by: java.lang.NullPointerException: Cannot invoke "org.javacord.api.entity.channel.TextChannel.sendMessage(String)" because the return value of "org.javacord.api.event.message.MessageCreateEvent.getChannel()" is null
at com.tikoJar.DTO.ResponseBuilder.addMessageResponse(ResponseBuilder.java:35)
at com.tikoJar.DTO.QueryHandler.addMessage(QueryHandler.java:74)
at com.tikoJar.DTO.QueryHandlerTest.lambda$TC5$0(QueryHandlerTest.java:68)
at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:53)
... 73 more
As you can see, the method I'm testing is calling and running the addMessageResponse() method in the ResponseBuilder class, even though I specified in my test that a custom exception should be thrown when attempting to call that method.
I've also tried specifying:
doNothing().when(responseBuilder).addMessageResponse(isA(Boolean.class), isA(Boolean.class));
... but the method still gets called and run. What can I do here?

Mockk AssertionError: Verification failed: call 1 of 1

///Here is my class
class State {
var state: Int = 10
}
open class Car {
var state:State = State()
fun changState(data: Int = 1) {
setState(data)
}
fun setState(data: Int = 0) {
state.state = data
}
}
/// Here is my Test
#Test
fun `test 1`() {
var mockCar = mockk<Car>()
every { mockCar.changState(any()) } just runs
every { mockCar.setState(any()) } just runs
mockCar.changState(10)
verify(exactly = 1) { mockCar.changState(any()) }
verify { mockCar.setState(any()) }
}
But it fails with this error
################################
java.lang.AssertionError: Verification failed: call 1 of 1: Car(#1).setState(any())) was not called.
Calls to same mock:
Car(#1).changState(10)
############################
You need to remove verify { mockCar.setState(any()) } - there is no way that this will ever be called, because you mocked
every { mockCar.changState(any()) } just runs
This means the stubbed method will do nothing, it just runs, so to speak.
I don't recommend writing tests that only test mocks, because it will lead to a bias that the code is fine when you just use outputs of what you think is correct behavior. Instead, write a separate unit test for Car.
For your use-case a mock is not the intended thing to use, you should be using a spy instead if you mix real method calls with mocked behavior.

IllegalArgumentException while running contract unit test in Kotlin (Corda)

When I try to run my Junit tests (Wrote in Kotlin) I get the following exception :
java.lang.IllegalArgumentException: Attempted to find dependent attachment for class javax/xml/bind/DatatypeConverter, but could not find a suitable candidate.
I tried to comment/decomment some lines in following code, it seems that the exception occurs when I call command()
class IRIssueTests {
class DummyCommand : TypeOnlyCommandData()
private val ledgerServices = MockServices(listOf("com.my.package.name"))
private val ALICE = TestIdentity(CordaX500Name(organisation = "Alice", locality = "TestLand", country = "US"))
#Test
fun mustIncludeIssueCommand() {
val ir = IRState(
UniqueIdentifier(),
mutableListOf(ALICE.party)
)
ledgerServices.ledger {
transaction {
output(IRContract.ID, ir)
command(listOf(ALICE.publicKey), DummyCommand())
fails()
}
transaction {
output(IRContract.ID, ir)
command(listOf(ALICE.publicKey), IRContract.Commands.Issue())
verifies()
}
}
}
}
I would like to understand why I'm getting this exception and how to resolve it to make my test passing
Kotlin tests must be run with JDK8.
Change configuration of JDK8 in your project before running tests.
This will avoid this exception

Retrying a complete testNG class and not just #Test method on skip/failure

I have implemented IRetryAnalyzer to re-run my failed test cases in my testNG class.
public class Retry implements IRetryAnalyzer {
private int retryCount = 0;
private int maxRetryCount = 1;
private int outcome;
// Below method returns 'true' if the test method has to be retried else 'false'
//and it takes the 'Result' as parameter of the test method that just ran
public boolean retry(ITestResult result) {
//outcome=result.getStatus();
if (retryCount < maxRetryCount ) {
result.getTestContext().getFailedTests().removeResult(result);
result.getTestContext().getSkippedTests().removeResult(result);
System.out.println("Retrying test " + result.getName() + " with status "
+ getResultStatusName(result.getStatus()) + " for the " + (retryCount+1) + " time(s).");
Reporter.log("Retrying test " + result.getName() + " with status "
+ getResultStatusName(result.getStatus()) + " for the " + (retryCount+1) + " time(s).");
retryCount++;
return true;
}
return false;
}
public String getResultStatusName(int status) {
String resultName = null;
if(status==1)
resultName = "SUCCESS";
if(status==2)
resultName = "FAILURE";
if(status==3)
resultName = "SKIP";
return resultName;
}
}
Now I have two Test methods:
#Test(priority = 3, enabled = true, dependsOnMethods={"step2"})
public void step3()
{.....................some code......}
#Test(priority = 4, enabled = true,dependsOnMethods={"step3"})
public void step4() {
....some codee..}
If step 3 fails, testNG skips step 4 which is as expected. But upon re-run it executes only step 3 and even if it passed at second attempt, step 4 which was skipped is not executed.
Is there any way I can re-run my whole TestNG failed class or an alternate solution to run my dependent cases after the #Test method they depend on fails.
Thanks in advance!
Please do the following to get this to work:
Remove the logic of removing failed and skipped tests from your org.testng.IRetryAnalyzer implementation i.e., the below two lines
result.getTestContext().getFailedTests().removeResult(result);
result.getTestContext().getSkippedTests().removeResult(result);
Include this logic of removing the skipped/failed tests from within either an #AfterMethod method (or) from within an afterInvocation() of a org.testng.IInvokedMethodListener listener implementation.
Something like below :
#AfterMethod
public void afterMethod(ITestResult result) {
IRetryAnalyzer retry = result.getMethod().getRetryAnalyzer();
if (retry == null) {
return;
}
result.getTestContext().getFailedTests().removeResult(result.getMethod());
result.getTestContext().getSkippedTests().removeResult(result.getMethod());
}
(or)
import org.testng.IInvokedMethod;
import org.testng.IInvokedMethodListener;
import org.testng.IRetryAnalyzer;
import org.testng.ITestResult;
public class Listener implements IInvokedMethodListener {
#Override
public void beforeInvocation(IInvokedMethod method, ITestResult testResult) {
}
#Override
public void afterInvocation(IInvokedMethod method, ITestResult result) {
IRetryAnalyzer retry = result.getMethod().getRetryAnalyzer();
if (retry == null) {
return;
}
result.getTestContext().getFailedTests().removeResult(result.getMethod());
result.getTestContext().getSkippedTests().removeResult(result.getMethod());
}
}
If you leverage the listener path, please ensure that you wire in the listener using one of the following ways :
via #Listeners annotation (or)
via <listeners> tag (or)
via service loaders in TestNG.
For more information refer to my blog post here.
Additing to the Krishnan Mahadevan answer, you can chose to skip
result.getTestContext().getFailedTests().removeResult(result.getMethod());
If you remove a failed test method then, depending on test case (step4) will be executed even when step3 gets fail after retry.

SimpleTester on CodeIgniter fails with "Class 'GroupTest' not found"

I'm trying to do a clean install SimpleTester on a new CodeIgniter application, following the instructions here: http://codeigniter.com/wiki/SimpleTester_-_Unit_testing_library
Everything's fine until step 6, when I add "simpletester" to the list of libraries that are autoloaded. As soon as I do that, visiting any page simply results in:
Fatal error: Class 'GroupTest' not found in
/path/to/app/application/libraries/simpletester.php on line 84
Grepping through the code for GroupTest I only see it referenced in comments, and in a readme file which states the following:
The GroupTest has been renamed TestSuite (see below).
It was removed completely in 1.1 in favour of this
name.
I tried modifying line 84 to replace GroupTest with TestSuite, but then I get the following error:
Fatal error: Call to undefined method TestSuite::addTestFile() in
/home/path/to/app/application/libraries/simpletester.php
on line 96
Is this a bug on their end? Has anyone seen this before?
I have run into the same issue. The GroupTest class can be found in test_case.php of version 1.0.1 of SimpleTest:
http://sourceforge.net/projects/simpletest/files/simpletest/simpletest_1.0.1/
Unfortunately, simply inserting v1.0.1 into the libraries folder doesn’t solve all the world’s problems. I no longer get the “Fatal error: Class ‘GroupTest’ not found ...” error, but I do get a segmentation fault and my site no longer works.
I have briefly tried to track down the issue but to no avail.
Note: I also responded on the CodeIgniter Wiki page containing the same question.
I had the same problem with a current project and found that the problem is that GroupTest was replaced with TestSuite which works a little differently.
This is the library code I use:
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
$libraryDir = APPPATH . 'libraries/simpletest';
if(!is_dir($libraryDir))
exit("Simpletest must be located in \"$libraryDir\"");
require_once $libraryDir . '/unit_tester.php';
require_once $libraryDir . '/mock_objects.php';
require_once $libraryDir . '/collector.php';
class SimpleTester
{
/**
* What reporter should be used for display.
* Could be either HtmlReporter, SmallReporter, MinimalReporter or ShowPasses.
*/
public $Reporter = 'MinimalReporter';
private $testDir;
private $testTitle;
private $fileExtension;
public function __construct($params = false)
{
$ci =& get_instance();
$ci->config->load('simpletester');
if($params == false) {
$params['runFromIPs'] = $ci->config->item('runFromIPs');
$params['testDir'] = $ci->config->item('testDir');
$params['fileExtension'] = $ci->config->item('fileExtension');
$params['autorun'] = $ci->config->item('autorun');
$params['reporter'] = $ci->config->item('reporter');
$params['testTitle'] = $ci->config->item('testTitle');
}
if(isset($params['runFromIPs']) && strpos($params['runFromIPs'], $ci->input->server('SERVER_ADDR') === FALSE))
{
// Tests won't be run automatically from this IP.
$params['autorun'] = FALSE;
}
// Check if call was an AJAX call. No point in running test
// if not seen and may break the call.
$header = 'CONTENT_TYPE';
if(!empty($_SERVER[$header])) {
// #todo Content types could be placed in config.
$ajaxContentTypes = array('application/x-www-form-urlencoded', 'multipart/form-data');
foreach ($ajaxContentTypes as $ajaxContentType) {
if(false !== stripos($_SERVER[$header], $ajaxContentType))
{
$params['autorun'] = FALSE;
break;
}
}
}
$this->testDir = $params['testDir'];
$this->testTitle = $params['testTitle'];
$this->fileExtension = $params['fileExtension'];
if(isset($params['reporter']))
$this->Reporter = $params['reporter'];
if($params['autorun'] == TRUE)
echo $this->Run();
}
/**
* Run the tests, returning the reporter output.
*/
public function Run()
{
// Save superglobals that might be tested.
if(isset($_SESSION)) $oldsession = $_SESSION;
$oldrequest = $_REQUEST;
$oldpost = $_POST;
$oldget = $_GET;
$oldfiles = $_FILES;
$oldcookie = $_COOKIE;
$test_suite = new TestSuite($this->testTitle);
// Add files in tests_dir
if(is_dir($this->testDir))
{
if($dh = opendir($this->testDir))
{
while(($file = readdir($dh)) !== FALSE)
{
// Test if file ends with php, then include it.
if(substr($file, -(strlen($this->fileExtension)+1)) == '.' . $this->fileExtension)
{
$test_suite->addFile($this->testDir . "/$file");
}
}
closedir($dh);
}
}
// Start the tests
ob_start();
$test_suite->run(new $this->Reporter);
$output_buffer = ob_get_clean();
// Restore superglobals
if(isset($oldsession)) $_SESSION = $oldsession;
$_REQUEST = $oldrequest;
$_POST = $oldpost;
$_GET = $oldget;
$_FILES = $oldfiles;
$_COOKIE = $oldcookie;
return $output_buffer;
}
}
// Html output reporter classes //////////////////////////////////////
/**
* Display passes
*/
class ShowPasses extends HtmlReporter
{
function ShowPasses()
{
$this->HtmlReporter();
}
function paintPass($message)
{
parent::paintPass($message);
print "<span class=\"pass\">Pass</span>: ";
$breadcrumb = $this->getTestList();
array_shift($breadcrumb);
print implode("->", $breadcrumb);
print "->$message<br />\n";
}
function _getCss()
{
return parent::_getCss() . ' .pass {color:green;}';
}
}
/**
* Displays a tiny div in upper right corner when ok
*/
class SmallReporter extends HtmlReporter
{
var $test_name;
function ShowPasses()
{
$this->HtmlReporter();
}
function paintHeader($test_name)
{
$this->test_name = $test_name;
}
function paintFooter($test_name)
{
if($this->getFailCount() + $this->getExceptionCount() == 0)
{
$text = $this->getPassCount() . " tests ok";
print "<div style=\"background-color:#F5FFA8; text-align:center; right:10px; top:30px; border:2px solid green; z-index:10; position:absolute;\">$text</div>";
}
else
{
parent::paintFooter($test_name);
print "</div>";
}
}
function paintFail($message)
{
static $header = FALSE;
if(!$header)
{
$this->newPaintHeader();
$header = TRUE;
}
parent::paintFail($message);
}
function newPaintHeader()
{
$this->sendNoCacheHeaders();
print "<style type=\"text/css\">\n";
print $this->_getCss() . "\n";
print "</style>\n";
print "<h1 style=\"background-color:red; color:white;\">$this->test_name</h1>\n";
print "<div style=\"background-color:#FBFBF0;\">";
flush();
}
}
/**
* Minimal only displays on error
*/
class MinimalReporter extends SmallReporter
{
function paintFooter($test_name)
{
if($this->getFailCount() + $this->getExceptionCount() != 0)
{
parent::paintFooter($test_name);
print "</div>";
}
}
}
Works fine for me I haven't tested all the different reporters yet though. But the default one works fine.
And this is how I use it:
$this->load->library('simpletester');
echo $this->simpletester->Run();
And my config file is:
$config['testDir'] = APPPATH . 'tests';
$config['runFromIPs'] = '127.0.0.1';
$config['reporter'] = 'HtmlReporter';
$config['autorun'] = false;
$config['fileExtension'] = 'php';
$config['testTitle'] = 'My Unit Tests';