PHP nasıl ünite testleri yazıyorsunuz?

11 Cevap php

Ben onlar hakkında ne kadar büyük her yerde okudum, ama nedense ben bir şey test etmem gerekiyordu tam olarak nasıl anlamaya görünüyor olamaz. Birisi belki örnek bir kod parçası sonrası olabilir ve nasıl test ederim? Zahmet olmazsa :)

11 Cevap

Eğer birim test için kullanabileceğiniz iki çerçeveler vardır. Simpletest ve PHPUnit, hangi tercihim. PHPUnit ana sayfasında testleri yazmak ve çalıştırmak için nasıl öğreticiler okumak. Bu oldukça kolay ve iyi tarif olduğunu.

Here Eğer SimpleTest ile birim test için iyi bir bakış bulabilirsiniz.

Şimdiye kadar öğrenmek için daha kolay bir 3 "çerçeve" var, - Simple Testi bile daha kolay, bu pHPT denir.

A primer can be found here: http://qa.php.net/write-test.php

Edit: Sadece örnek kod için isteğinizi gördüm.

Diyelim ki adlı bir dosyada aşağıdaki işlevi olduğunu varsayalım lib.php:

<?php
function foo($bar)
{
  return $bar;
}
?>

Gerçekten basit ve yalındır, içinde geçmesi parametre döndürülür. Yani bu fonksiyon için bir test bakalım, biz test dosyasını çağırmak foo.phpt olacak:

--TEST--
foo() function - A basic test to see if it works. :)
--FILE--
<?php
include 'lib.php'; // might need to adjust path if not in the same dir
$bar = 'Hello World';
var_dump(foo($bar));
?>
--EXPECT--
string(11) "Hello World"

Özetle, biz değer "Hello World" ile parametresini $bar sağlamak ve işlev çağrısı biz var_dump() yanıtı foo().

Bu testi çalıştırmak için kullanın: pear run-test path/to/foo.phpt

Bu çoğu durumda oldukça yaygındır, sisteminizde a working install of PEAR gerektirir. Yüklemeniz gerekiyorsa, ben mevcut son sürümünü yüklemek için önerilir. Eğer (vb, ama OS sağlamak) sormaya çekinmeyin, bunu kurmak için yardıma ihtiyacım var.

Bunu karşılamak için kodlama stilini değiştirmek sürece Birim test çok etkili değildir. Ben özellikle This post, Google Testing Blog gezen öneririz.

Phpunit alın. Kullanımı çok kolaydır.

Sonra çok basit iddialar ile başlar. Eğer başka bir şey girmeden önce assertEquals ile çok yapabilirsiniz. Yani ayaklarınızı ıslak almak için iyi bir yoldur.

Ayrıca, (size soru TDD etiketi verdi beri) ilk test yazıyorum deneyin ve sonra kod yazmak isteyebilirsiniz. Eğer daha önce bu yapmadıysanız bir göz açıcı.

require_once 'ClassYouWantToTest';
require_once 'PHPUnit...blah,blah,whatever';

class ClassYouWantToTest extends PHPUnit...blah,blah,whatever
{
    private $ClassYouWantToTest;

   protected function setUp ()
    {
        parent::setUp();
        $this->ClassYouWantToTest = new ClassYouWantToTest(/* parameters */);
    }

    protected function tearDown ()
    {
        $this->ClassYouWantToTest = null;
        parent::tearDown();
    }

    public function __construct ()
    {   
    	// not really needed
    }

    /**
     * Tests ClassYouWantToTest->methodFoo()
     */
    public function testMethodFoo ()
    {
        $this->assertEquals(
            $this->ClassYouWantToTest->methodFoo('putValueOfParamHere), 'expectedOutputHere);

    /**
     * Tests ClassYouWantToTest->methodBar()
     */
    public function testMethodFoo ()
    {
        $this->assertEquals(
            $this->ClassYouWantToTest->methodBar('putValueOfParamHere), 'expectedOutputHere);
}

Şunlar da hoşunuza gidebilir this discussion of PHP unit test frameworks.

I şeyin başkasının yolunu öğrenmek için zaman yoktu çünkü benim kendi haddelenmiş, bu buraya yazabilmek için uyarlamak için, 10 kadar yazmak için yaklaşık 20 dakika sürdü.

Unittesting bana very yararlıdır.

Bu çok uzun ama kendisi açıklar ve altındaki bir örnek yoktur.

/**
 * Provides Assertions
 **/
class Assert
{
    public static function AreEqual( $a, $b )
    {
    	if ( $a != $b )
    	{
    		throw new Exception( 'Subjects are not equal.' );
    	}
    }
}

/**
 * Provides a loggable entity with information on a test and how it executed
 **/
class TestResult
{
    protected $_testableInstance = null;

    protected $_isSuccess = false;
    public function getSuccess()
    {
    	return $this->_isSuccess;
    }

    protected $_output = '';
    public function getOutput()
    {
    	return $_output;
    }
    public function setOutput( $value )
    {
    	$_output = $value;
    }

    protected $_test = null;
    public function getTest()
    {
    	return $this->_test;
    }

    public function getName()
    {
    	return $this->_test->getName();
    }
    public function getComment()
    {
    	return $this->ParseComment( $this->_test->getDocComment() );
    }

    private function ParseComment( $comment )
    {
    	$lines = explode( "\n", $comment );
    	for( $i = 0; $i < count( $lines ); $i ++ )
    	{
    		$lines[$i] = trim( $lines[ $i ] );
    	}
    	return implode( "\n", $lines );
    }

    protected $_exception = null;
    public function getException()
    {
    	return $this->_exception;
    }

    static public function CreateFailure( Testable $object, ReflectionMethod $test, Exception $exception )
    {
    	$result = new self();
    	$result->_isSuccess = false;
    	$result->testableInstance = $object;
    	$result->_test = $test;
    	$result->_exception = $exception;

    	return $result;
    }
    static public function CreateSuccess( Testable $object, ReflectionMethod $test )
    {
    	$result = new self();
    	$result->_isSuccess = true;
    	$result->testableInstance = $object;
    	$result->_test = $test;

    	return $result;
    }
}

/**
 * Provides a base class to derive tests from
 **/
abstract class Testable
{
    protected $test_log = array();

    /**
     * Logs the result of a test. keeps track of results for later inspection, Overridable to log elsewhere.
     **/
    protected function Log( TestResult $result )
    {
    	$this->test_log[] = $result;

    	printf( "Test: %s was a %s %s\n"
    		,$result->getName()
    		,$result->getSuccess() ? 'success' : 'failure'
    		,$result->getSuccess() ? '' : sprintf( "\n%s (lines:%d-%d; file:%s)"
    			,$result->getComment()
    			,$result->getTest()->getStartLine()
    			,$result->getTest()->getEndLine()
    			,$result->getTest()->getFileName()
    			)
    		);

    }
    final public function RunTests()
    {
    	$class = new ReflectionClass( $this );
    	foreach( $class->GetMethods() as $method )
    	{
    		$methodname = $method->getName();
    		if ( strlen( $methodname ) > 4 && substr( $methodname, 0, 4 ) == 'Test' )
    		{
    			ob_start();
    			try
    			{
    				$this->$methodname();
    				$result = TestResult::CreateSuccess( $this, $method );
    			}
    			catch( Exception $ex )
    			{
    				$result = TestResult::CreateFailure( $this, $method, $ex );
    			}
    			$output = ob_get_clean();
    			$result->setOutput( $output );
    			$this->Log( $result );
    		}
    	}
    }
}

/**
 * a simple Test suite with two tests
 **/
class MyTest extends Testable
{
    /**
     * This test is designed to fail
     **/
    public function TestOne()
    {
    	Assert::AreEqual( 1, 2 );
    }

    /**
     * This test is designed to succeed
     **/
    public function TestTwo()
    {
    	Assert::AreEqual( 1, 1 );
    }
}

// this is how to use it.
$test = new MyTest();
$test->RunTests();

Bu çıkışlar:

Test: TestOne was a failure 
/**
* This test is designed to fail
**/ (lines:149-152; file:/Users/kris/Desktop/Testable.php)
Test: TestTwo was a success 

Zaten verilen test çerçeveler hakkında mükemmel öneriler yanında, Symfony gibi, test inşa otomatik sahiptir PHP web çerçeveler biri ile uygulama bina veya CakePHP? Bazen sadece test yöntemleri düşmesi için bir yere sahip bazı insanlar otomatik test ve TDD ile ilişkilendirmek start-up sürtünmeyi azaltır.

Basit testler VE belgeler için, php-doctest oldukça güzel ve ayrı bir dosya açmak zorunda değilsiniz çünkü başlamak için gerçekten kolay yolu. Aşağıdaki fonksiyonu düşünün:

/**
* Sums 2 numbers
* <code>
* //doctest: add
* echo add(5,2);
* //expects:
* 7
* </code>
*/
function add($a,$b){
    return $a + $b;   
}

Şimdi phpdt (php-doctest komut satırı koşucu) ile bu dosyayı çalıştırırsanız 1 testi çalıştırmak olacaktır. Doctest içinde bulunan < code> bloğu. Doctest Python kökenli ve yararlı veren ve gayet iyi kod çalışması gerekiyordu nasıl koşulabilir örnekleri. I phpunit kullanmak - kodu kendisi test durumlarda çöp kadar olur ama daha resmi bir tdd'nin kütüphanede yanında yararlı olduğunu tespit ettik çünkü sadece bunu kullanamaz.

Bu cevap 1 here (o doctest vs birimi değil) güzel özetliyor.

Codeception testleri çok yaygın birim testleri gibi ama alaycı ve stubbing gereken şeyleri çok güçlü.

İşte örnek denetleyici testidir. Taslakları oluşturulan nasıl kolayca dikkat edin. Eğer metodunu kontrol Nasıl kolayca çağrıldı.

<?php
use Codeception\Util\Stub as Stub;

const VALID_USER_ID = 1;
const INVALID_USER_ID = 0;

class UserControllerCest {
public $class = 'UserController';


public function show(CodeGuy $I) {
    // prepare environment
    $I->haveFakeClass($controller = Stub::makeEmptyExcept($this->class, 'show'));
    $I->haveFakeClass($db = Stub::make('DbConnector', array('find' => function($id) { return $id == VALID_USER_ID ? new User() : null ))); };
    $I->setProperty($controller, 'db', $db);

    $I->executeTestedMethodOn($controller, VALID_USER_ID)
        ->seeResultEquals(true)
        ->seeMethodInvoked($controller, 'render');

    $I->expect('it will render 404 page for non existent user')
        ->executeTestedMethodOn($controller, INVALID_USER_ID)
        ->seeResultNotEquals(true)
        ->seeMethodInvoked($controller, 'render404','User not found')
        ->seeMethodNotInvoked($controller, 'render');
}
}

Ayrıca diğer serin şeyler vardır. Vb veritabanı durumunu, dosya sistemi, test edebilirsiniz

Ben bir sürü bilgi zaten burada olduğunu biliyorum, ama bu yine de Google aramalarında gösterir beri ben de listesine Chinook Test Suite ekleyebilirsiniz. Bu basit ve küçük bir test çerçevedir.

You can easily test your classes with it and also create mock objects. You run the tests through a web browser and (not yet) through a console. In the browser you can specify what test class or even what test method to run. Or you can simply run all tests.

Github sayfasından bir ekran görüntüsü:

Chinook Birim Test framework

Ne i gibi bu konuda size testleri iddia yoludur. Bu, sözde "akıcı yoluyla" ile yapılır. Örnek:

$this->Assert($datetime)->Should()->BeAfter($someDatetime);

Ve sahte nesneleri oluşturma (sözdizimi gibi akıcı) ile de bir esinti:

$mock = new CFMock::Create(new DummyClass());
$mock->ACallTo('SomeMethod')->Returns('some value');

Neyse, daha fazla bilgi yanı sıra bir örnek kod ile github sayfasında bulunabilir:

https://github.com/w00/Chinook-TestSuite

Burada çok burada yeniden yazılan çok şey var, ama bir great article phpt kullanarak üzerindedir. Bu genellikle göz ardı edilir çevresindeki phpt yönlerini bir dizi kapsar, bu yüzden sadece bir test yazıyorum ötesinde php bilginizi genişletmek için bir okuma değer olabilir. Neyse yazı da yazmaya testleri tartışıyor!

Tartışmanın ana noktaları

  1. PHP işin nasıl marjinal belgelenmiş yönleri (ya da bu konuda hemen hemen herhangi bir bölümünü) keşfedin
  2. Kendi PHP kodu için basit birim testleri yazmak
  3. Bir uzantısı parçası olarak testleri yazmak veya internals veya QA gruplar için potansiyel bir hata iletmek için