# Advanced PHP autograding

In this guide, we explore the advanced grading options available for PHP assignments. For more information about setting up a PHP assignment from scratch, see:

{% content-ref url="create-your-first-php-assignment" %}
[create-your-first-php-assignment](https://help.codegrade.com/automatic-grading-guides/php/create-your-first-php-assignment)
{% endcontent-ref %}

## Unit tests with PHPUnit

PHPUnit is an industry-standard unit testing framework for PHP. It is particularly useful for grading assignments that require students to write functions and classes. Using PHPUnit unit tests offers several advantages over conventional IO tests, including the ability to use assertions, parametrize test cases, and provide better feedback for students. For further documentation about PHPUnit we recommend [this online resource](https://phpunit.de/documentation.html).

\
Consider the example submission `Fibonacci.php` file below:

```php
<?php

function PrintFibonacci($n) {
    $num1 = 0;
    $num2 = 1;

    echo "$num1\n";
    echo "$num2\n";

    for ($i = 2; $i < $n; $i++) {
        $num3 = $num1 + $num2;
        echo "$num3\n";
        $num1 = $num2;
        $num2 = $num3;
    }
}

function ComputeFibonacci($n) {
    if ($n == 0) {
        return 0;
    }
    if ($n == 1) {
        return 1;
    }
    if ($n == 2) {
        return 1;
    }
    $num1 = 0;
    $num2 = 1;

    for ($i = 2; $i <= $n; $i++) {
        $num3 = $num1 + $num2;
        $num1 = $num2;
        $num2 = $num3;
    }
    return $num3;
}

$number = (int)readline("Enter the number of terms: ");
PrintFibonacci($number);
```

Our goal is to unit test the `ComputeFibonacci` function. Our tests are defined in the following `FibonacciTests.php` file:

```php
<?php

use PHPUnit\Framework\TestCase;

include('./Fibonacci.php');

class FibonacciTests extends TestCase
{
    public function testFibonacciZero()
    {
        $this->assertEquals(0, ComputeFibonacci(0));
    }

    public function testFibonacciOne()
    {
        $this->assertEquals(1, ComputeFibonacci(5));
    }

    public function testFibonacciTwo()
    {
        $this->assertEquals(1, ComputeFibonacci(2));
    }

    public function testFibonacciThree()
    {
        $this->assertEquals(2, ComputeFibonacci(3));
    }

    public function testFibonacciTen()
    {
        $this->assertEquals(55, ComputeFibonacci(10));
    }

    public function testFibonacciTwenty()
    {
        $this->assertEquals(6765, ComputeFibonacci(20));
    }
}
```

### Setup: Install PHPUnit

After installing PHP as described in the previous guide, we can use Script Block to install Composer, a PHP dependency management framework, and then PHPUnit.

<div data-full-width="true"><figure><img src="https://2172486256-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MKAQsDlg_P20iQy3JDs%2Fuploads%2FR39Y9skdWQ0fW05kySvH%2FScreenshot%202024-05-24%20at%2015.29.58.png?alt=media&#x26;token=864b5c42-3e14-4ea7-a50a-c40064456c2a" alt=""><figcaption></figcaption></figure></div>

In the `Install php dependecies` Script block above, we run the following Bash script:

{% code fullWidth="true" %}

```shell
set -e

# install composer
yes | sudo apt install php-cli unzip
curl -sS https://getcomposer.org/installer -o /tmp/composer-setup.php
HASH=`curl -sS https://composer.github.io/installer.sig`
php -r "if (hash_file('SHA384', '/tmp/composer-setup.php') === '$HASH') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
sudo php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer

# install php dependencies
sudo apt-get update
sudo apt-get install php-xml
sudo apt-get install php-mbstring

# install php tools
composer require --dev phpunit/phpunit:^9.5

# add the tools to the path
echo 'export PATH=$PATH:~/vendor/phpunit' >> ~/.cg_bash_env
echo 'export PATH=$PATH:~/vendor/bin' >> ~/.cg_bash_env
```

{% endcode %}

### Test execution

Once we are done with the Setup Phase in AutoTest, we can move on to the next Tests phase. Here, we first need to upload our testing file `FibonacciTests.php`  using an Upload Files Block.

We can then run our  unit tests using a Custom Test Block as shown below:

<div data-full-width="true"><figure><img src="https://2172486256-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MKAQsDlg_P20iQy3JDs%2Fuploads%2FeibsKo5SekIQ5mNOW2Wb%2FScreenshot%202024-05-24%20at%2016.01.28.png?alt=media&#x26;token=175044e6-0da6-4521-8723-1d573c440e21" alt=""><figcaption></figcaption></figure></div>

The Custom Test Block runs the following commands:

{% code fullWidth="true" %}

```bash
set -e

# move the necessary files to the current directory
cp $UPLOADED_FILES/* . 
mv  ~/composer.json .

# wrap a bash script around phpunit (needed to handle the exit code returned by phpunit)
cat <<EOF > script.sh
phpunit --log-junit report.xml FibonacciTests.php 
cg junitxml report.xml
exit 0
EOF

# run the script that calls phpunit
chmod +x script.sh 
./script.sh
```

{% endcode %}

Notice that you can hide these commands from the students using a Hide Block.

The results of the unit tests will be shown to the student as below:

<div data-full-width="true"><figure><img src="https://2172486256-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MKAQsDlg_P20iQy3JDs%2Fuploads%2FHAUlAQwb3vhfdE0TptUU%2FScreenshot%202024-05-24%20at%2016.17.42.png?alt=media&#x26;token=170d2f91-bf5c-45b7-8a18-29fece26b62e" alt=""><figcaption></figcaption></figure></div>

## Code Quality Tests with PHP\_CodeSniffer

PHP\_CodeSniffer is an industry-standard linter for PHP that allows you to enforce rules from various coding standards. It is a useful tool for enforcing code styling best practices for beginner programmers. To read more about PHP\_CodeSniffer, we recommend [this online resource](https://github.com/squizlabs/PHP_CodeSniffer/wiki/Configuration-Options#setting-the-default-coding-standard).

### Setup: Install php\_codesniffer

We can repeat the same steps described in the section above for installing PHPUnit, just now the installing script is slightly different:

```bash
set -e

# install composer
yes | sudo apt install php-cli unzip
curl -sS https://getcomposer.org/installer -o /tmp/composer-setup.php
HASH=`curl -sS https://composer.github.io/installer.sig`
php -r "if (hash_file('SHA384', '/tmp/composer-setup.php') === '$HASH') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
sudo php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer

# install php dependencies
sudo apt-get update
sudo apt-get install php-xml
sudo apt-get install php-mbstring

# install php tools
composer require --dev squizlabs/php_codesniffer

# add the tools to the path
echo 'export PATH=$PATH:~/vendor/phpunit' >> ~/.cg_bash_env
echo 'export PATH=$PATH:~/vendor/bin' >> ~/.cg_bash_env
```

### Test execution

We can run PHP\_Codesniffer on a student file, `Fibonacci`.php\` in the example below, through a Custom Test Block:

<div data-full-width="true"><figure><img src="https://2172486256-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MKAQsDlg_P20iQy3JDs%2Fuploads%2FcWC4BrWAE56xw1FQzSY9%2FScreenshot%202024-05-24%20at%2016.21.21.png?alt=media&#x26;token=96901696-43cb-4f83-9afa-d7f782d814bf" alt=""><figcaption></figcaption></figure></div>

Within the Custom Test Block, we run the following script:

{% code fullWidth="true" %}

```bash
set -e

# wrap a bash script around phpcs (needed to handle the exit code returned by phpcs)
cat <<EOF > script.sh
phpcs --report=checkstyle --standard=PSR12 ./Fibonacci.php > report.xml
cg checkstyle parse report.xml
exit 0
EOF

# run the script that calls phpcs
chmod +x script.sh 
./script.sh
```

{% endcode %}

Running the Code Quality Test will produce inline comments within the student submission, as shown below:

<div data-full-width="true"><figure><img src="https://2172486256-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MKAQsDlg_P20iQy3JDs%2Fuploads%2FgWQ6ovixo6i5cJW4qv0d%2FScreenshot%202025-08-05%20at%2014.13.00.png?alt=media&#x26;token=37825c3e-307f-4163-9961-82d771e43f4a" alt=""><figcaption></figcaption></figure></div>
