Skip to content

Instantly share code, notes, and snippets.

@XedinUnknown
Created May 25, 2018 15:17
Show Gist options
  • Select an option

  • Save XedinUnknown/43f75651f2fea43485d6169efa40fe8d to your computer and use it in GitHub Desktop.

Select an option

Save XedinUnknown/43f75651f2fea43485d6169efa40fe8d to your computer and use it in GitHub Desktop.

Revisions

  1. XedinUnknown created this gist May 25, 2018.
    166 changes: 166 additions & 0 deletions trait-test-template
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,166 @@
    <?php
    #if (${NAMESPACE})

    namespace ${NAMESPACE};

    #end

    #if (${TESTED_NAME} && ${NAMESPACE} && !${TESTED_NAMESPACE})
    use ${TESTED_NAME};
    #elseif (${TESTED_NAME} && ${TESTED_NAMESPACE} && ${NAMESPACE} != ${TESTED_NAMESPACE})
    use ${TESTED_NAMESPACE}\\${TESTED_NAME} as TestSubject;
    #end

    use Xpmock\TestCase;
    use Exception as RootException;
    use PHPUnit_Framework_MockObject_MockObject as MockObject;
    use PHPUnit_Framework_MockObject_MockBuilder as MockBuilder;

    /**
    * Tests {@see TestSubject}.
    *
    * @since [*next-version*]
    */
    class ${NAME} extends TestCase
    {
    /**
    * The class name of the test subject.
    *
    * @since [*next-version*]
    */
    const TEST_SUBJECT_CLASSNAME = '${TESTED_NAMESPACE}\\${TESTED_NAME}';

    /**
    * Creates a new instance of the test subject.
    *
    * @since [*next-version*]
    *
    * @param array \$methods The methods to mock.
    *
    * @return MockObject The new instance.
    */
    public function createInstance(\$methods = [])
    {
    is_array(\$methods) && \$methods = \$this->mergeValues(\$methods, [
    '__',
    ]);

    \$mock = \$this->getMockBuilder(static::TEST_SUBJECT_CLASSNAME)
    ->setMethods(\$methods)
    ->getMockForTrait();

    \$mock->method('__')
    ->will(\$this->returnArgument(0));

    return \$mock;
    }

    /**
    * Merges the values of two arrays.
    *
    * The resulting product will be a numeric array where the values of both inputs are present, without duplicates.
    *
    * @since [*next-version*]
    *
    * @param array \$destination The base array.
    * @param array \$source The array with more keys.
    *
    * @return array The array which contains unique values
    */
    public function mergeValues(\$destination, \$source)
    {
    return array_keys(array_merge(array_flip(\$destination), array_flip(\$source)));
    }

    /**
    * Creates a mock that both extends a class and implements interfaces.
    *
    * This is particularly useful for cases where the mock is based on an
    * internal class, such as in the case with exceptions. Helps to avoid
    * writing hard-coded stubs.
    *
    * @since [*next-version*]
    *
    * @param string \$className Name of the class for the mock to extend.
    * @param string[] \$interfaceNames Names of the interfaces for the mock to implement.
    *
    * @return MockBuilder The builder for a mock of an object that extends and implements
    * the specified class and interfaces.
    */
    public function mockClassAndInterfaces(\$className, \$interfaceNames = [])
    {
    \$paddingClassName = uniqid(\$className);
    \$definition = vsprintf('abstract class %1\$s extends %2\$s implements %3\$s {}', [
    \$paddingClassName,
    \$className,
    implode(', ', \$interfaceNames),
    ]);
    eval(\$definition);

    return \$this->getMockBuilder(\$paddingClassName);
    }

    /**
    * Creates a mock that uses traits.
    *
    * This is particularly useful for testing integration between multiple traits.
    *
    * @since [*next-version*]
    *
    * @param string[] \$traitNames Names of the traits for the mock to use.
    *
    * @return MockBuilder The builder for a mock of an object that uses the traits.
    */
    public function mockTraits(\$traitNames = [])
    {
    \$paddingClassName = uniqid('Traits');
    \$definition = vsprintf('abstract class %1\$s {%2\$s}', [
    \$paddingClassName,
    implode(
    ' ',
    array_map(
    function (\$v) {
    return vsprintf('use %1\$s;', [\$v]);
    },
    \$traitNames)),
    ]);
    var_dump(\$definition);
    eval(\$definition);

    return \$this->getMockBuilder(\$paddingClassName);
    }

    /**
    * Creates a new exception.
    *
    * @since [*next-version*]
    *
    * @param string \$message The exception message.
    *
    * @return RootException|MockObject The new exception.
    */
    public function createException(\$message = '')
    {
    \$mock = \$this->getMockBuilder('Exception')
    ->setConstructorArgs([\$message])
    ->getMock();

    return \$mock;
    }

    /**
    * Tests whether a valid instance of the test subject can be created.
    *
    * @since [*next-version*]
    */
    public function testCanBeCreated()
    {
    \$subject = \$this->createInstance();

    \$this->assertInternalType(
    'object',
    \$subject,
    'A valid instance of the test subject could not be created.'
    );
    }
    }