2012-01-28 16 views
5

अपलोड का परीक्षण करने के लिए मैं बाइनरी डेटा के साथ php://input कैसे पॉप्युलेट कर सकता हूं? (या अन्यथा खंडित अपलोड का परीक्षण करें)। मैं अपने फ्रंटएंड के रूप में plupload का उपयोग कर रहा हूं, और मैं अपने बैकएंड को एकजुट करना चाहता हूं।PHPUnit परीक्षण बाइनरी डेटा अपलोड

public function recieve($file = 'file') 
{ 
    // Get parameters 
    $chunk = isset($_REQUEST["chunk"]) ? intval($_REQUEST["chunk"]) : 0; 
    $chunks = isset($_REQUEST["chunks"]) ? intval($_REQUEST["chunks"]) : 0; 
    $fileName = isset($_REQUEST["name"]) ? $_REQUEST["name"] : ''; 
    $targetDir = $this->_uploadDir; 

    // Clean the fileName for security reasons 
    $fileName = preg_replace('/[^\w\._]+/', '_', $fileName); 

    // Make sure the fileName is unique but only if chunking is disabled 
    if ($chunks < 2 && file_exists($targetDir . DIRECTORY_SEPARATOR . $fileName)) { 
     $ext = strrpos($fileName, '.'); 
     $fileName_a = substr($fileName, 0, $ext); 
     $fileName_b = substr($fileName, $ext); 

     $count = 1; 
     while (file_exists(
       $targetDir . DIRECTORY_SEPARATOR . $fileName_a . '_' . $count . $fileName_b)) { 
      $count++; 
     } 

     $fileName = $fileName_a . '_' . $count . $fileName_b; 
    } 

    $filePath = $targetDir . DIRECTORY_SEPARATOR . $fileName; 

    // Create target dir 
    if (!file_exists($targetDir)) { 
     if (!is_writable(dirname($targetDir))) { 
      $this->_messages[] = 'Cannot write to ' . dirname($targetDir) . ' for mkdir'; 
      return false; 
     } 
     mkdir($targetDir, 0777, true); 
    } 

    // Check permissions 
    if (!is_writable($targetDir)) { 
     $this->_messages[] = 'Unable to write to temp directory.'; 
     return false; 
    } 

    // Look for the content type header 
    $contentType = null; 
    if (isset($_SERVER["HTTP_CONTENT_TYPE"])) 
     $contentType = $_SERVER["HTTP_CONTENT_TYPE"]; 

    if (isset($_SERVER["CONTENT_TYPE"])) 
     $contentType = $_SERVER["CONTENT_TYPE"]; 

    // Handle non multipart uploads older WebKit versions didn't support multipart in HTML5 
    if (strpos($contentType, "multipart") !== false) { 
     if (isset($_FILES[$file]['tmp_name']) && is_uploaded_file($_FILES[$file]['tmp_name'])) { 
      // Open temp file 
      $out = fopen("{$filePath}.part", $chunk == 0 ? "wb" : "ab"); 
      if ($out) { 
       // Read binary input stream and append it to temp file 
       $in = fopen($_FILES[$file]['tmp_name'], "rb"); 

       if ($in) { 
        while ($buff = fread($in, 4096)) { 
         fwrite($out, $buff); 
        } 
       } else { 
        $this->_messages[] = 'Failed to open input stream.'; 
        return false; 
       } 
       fclose($in); 
       fclose($out); 
       unlink($_FILES[$file]['tmp_name']); 
      } else { 
       $this->_messages[] = 'Failed to open output stream.'; 
       return false; 
      } 
     } else { 
      $this->_messages[] = 'Failed to move uploaded file.'; 
      return false; 
     } 
    } else { 
     // Open temp file 
     $out = fopen("{$filePath}.part", $chunk == 0 ? "wb" : "ab"); 
     if ($out) { 
      // Read binary input stream and append it to temp file 
      $in = fopen("php://input", "rb"); 
      if ($in) { 
       while ($buff = fread($in, 4096)) { 
        fwrite($out, $buff); 
       } 
      } else { 
       $this->_messages[] = 'Failed to open input stream.'; 
       return false; 
      } 
      fclose($in); 
      fclose($out); 
     } else { 
      $this->_messages[] = 'Failed to open output stream.'; 
      return false; 
     } 
    } 

    // Check if file upload is complete 
    if (!$chunks || $chunk == $chunks - 1) { 
     // Strip the temp .part suffix off 
     rename("{$filePath}.part", $filePath); 
     return $filePath; 
    } 
} 

* संपादित:

जोड़ा अधिक कोड, दिखाने के क्या मैं इकाई परीक्षण करना चाहते हैं

+0

क्या आप ** इकाई ** या एकीकरण परीक्षण करना चाहते हैं? यदि आप एकीकरण करना चाहते हैं तो इसका परीक्षण करें: क्या विस्तारित है? वेबसर्वर के माध्यम से जा रहा है या नहीं? $ _REQUEST एक एकीकरण परीक्षण का सुझाव देता है लेकिन मैं जवाब देने से पहले पूछना चाहता था। – edorian

+0

मैं सर्वर कोड को प्राप्त करने के लिए सर्वर कोड का परीक्षण करना चाहता हूं, यह सत्यापित करने के लिए कि किसी भी अपलोड की गई फ़ाइल को अपेक्षित माना जाएगा –

+0

फिर से पूछने के लिए खेद है लेकिन मैं इसका पालन नहीं कर रहा हूं। आप कोड के इस टुकड़े को यूनिट परीक्षण कर सकते हैं या वेब सर्वर के माध्यम से फ़ाइल अपलोड करने का परीक्षण कर सकते हैं, दोनों चीजें थोड़ी-थोड़ी समझ में नहीं आती हैं। यदि आप एक "नकली" फ़ाइल अपलोड करना चाहते हैं जो एकीकरण परीक्षण है। हो सकता है कि यहां शब्द ही मुद्दे हैं? http: // stackoverflow।कॉम/प्रश्न/516572/एम-आई-यूनिट-परीक्षण-या-एकीकरण-परीक्षण – edorian

उत्तर

6

लगता है यह नियमित रूप से PHPUnit परीक्षण के साथ नहीं किया जा सकता है, लेकिन मैं पर PHPUnit साथ .phpt परीक्षण एकीकृत करने के लिए एक रास्ता मिल गया:

--TEST-- 
Example test emulating a file upload 
--POST_RAW-- 
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryfywL8UCjFtqUBTQn 

------WebKitFormBoundaryfywL8UCjFtqUBTQn 
Content-Disposition: form-data; name="file"; filename="example.txt" 
Content-Type: text/plain 

Contents of text file here 

------WebKitFormBoundaryfywL8UCjFtqUBTQn 
Content-Disposition: form-data; name="submit" 

Upload 
------WebKitFormBoundaryfywL8UCjFtqUBTQn-- 
--FILE-- 
<?php 
require __DIR__ . '/Upload.php'; 

$upload = new Upload(); 
$file = $upload->recieve('file'); 

var_dump(file_exists($file)); 
?> 
--EXPECT-- 
bool(true) 

और: http://qafoo.com/blog/013_testing_file_uploads_with_php.html

संदर्भ के लिए, uploadTest.phpt संबंधित PHPUnit परीक्षण एकीकरण:

<?php 
require_once 'PHPUnit/Extensions/PhptTestCase.php'; 
class UploadExampleTest extends PHPUnit_Extensions_PhptTestCase 
{ 
    public function __construct() 
    { 
     parent::__construct(__DIR__ . '/uploadTest.phpt'); 
    } 
} 
+0

यह एकीकरण परीक्षण के लिए एकदम सही है। –

+0

+1, अच्छा समाधान। – hakre

+0

इसे काम नहीं कर सकता है। परीक्षण में 'GET' या' POST' उपयोग के कारण, सभी * .phpt परीक्षण निष्पादन की आवश्यकता '- cgi' विकल्प की आवश्यकता है। दस्तावेज़ भी। राज्य, कि वर्तमान में केवल सर्वर-test.php' के साथ उपलब्ध है और मुझे नहीं पता कि यह कहां देखना है और यह मेरे परीक्षण से कैसे जुड़ा हुआ है। – Eugene

2

सबसे पहले, आप के लिए

इस कोड का टुकड़ा परीक्षण करने के लिए मैं चाहता हूँ है यह कोड यूनिट परीक्षण के लिए काफी आसान है अगर यह एक 200 लाइन विधि नहीं था! इकाई छोटा - परीक्षण छोटा है। आप getFileName(), getContentType(), isChunked() या getChunkDetails(), transferChunk() इत्यादि निकाल सकते हैं। इनमें से कई विधियां बहुत कम होंगी और आपको संपूर्ण अपलोड सेट किए बिना पूरी तरह से परीक्षण करने की अनुमति मिल जाएगी। यहाँ एक उदाहरण है, getContentType():

public function getContentType() { 
    if (isset($_SERVER["CONTENT_TYPE"])) 
     return $_SERVER["CONTENT_TYPE"]; 

    if (isset($_SERVER["HTTP_CONTENT_TYPE"])) 
     return $_SERVER["HTTP_CONTENT_TYPE"]; 

    throw new FileTransferException('Unknown content type'); 
} 

इस विधि के लिए परीक्षण सीधी-सपाट हैं।

/** 
* @expectedException FileTransferException 
*/ 
public function testUnknownContentType() { 
    $fixture = new FileTransfer(); 
    unset($_SERVER["CONTENT_TYPE"]); 
    unset($_SERVER["HTTP_CONTENT_TYPE"]); 
    $fixture->getContentType(); 
} 

public function testRegularContentType() { 
    $fixture = new FileTransfer(); 
    $_SERVER["CONTENT_TYPE"] = 'regular'; 
    unset($_SERVER["HTTP_CONTENT_TYPE"]); 
    self::assertEquals('regular', $fixture->getContentType()); 
} 

public function testHttpContentType() { 
    $fixture = new FileTransfer(); 
    unset($_SERVER["CONTENT_TYPE"]); 
    $_SERVER["HTTP_CONTENT_TYPE"] = 'http'; 
    self::assertEquals('http', $fixture->getContentType()); 
} 

public function testRegularContentTypeTakesPrecedence() { 
    $fixture = new FileTransfer(); 
    $_SERVER["HTTP_CONTENT_TYPE"] = 'http'; 
    $_SERVER["CONTENT_TYPE"] = 'regular'; 
    self::assertEquals('regular', $fixture->getContentType()); 
} 

एक बार जब आप आसान सामान के साथ कोड पुनर्संशोधित है, तो आप मैं के सभी/हे एक अलग वर्ग में से निपटने निकाल सकते हैं। ऐसा करने से आप गैर-आई/ओ कोड का परीक्षण करते समय एक नकली वस्तु का उपयोग कर सकते हैं, जिसका अर्थ है कि आपको नकली डेटा के साथ वास्तविक फ़ाइलों या php://input पर भरोसा नहीं करना पड़ेगा। यह "यूनिट परीक्षण" का "यूनिट" हिस्सा है: छोटे, टेस्टेबल इकाइयों में अपना कोड तोड़ना, और व्यावहारिक समीकरण से अन्य इकाइयों को हटा देना।

निकाले गए I/O-हैंडलिंग क्लास में, कॉल को is_uploaded_file() पर रखें और इनपुट स्ट्रीम को अलग-अलग तरीकों से खोलें, उदा। isUploadedFile() और openInputStream()। परीक्षण करते समय आप उन अंतर्निहित तंत्रों को मजाक करने के बजाय उन तरीकों का नकल कर सकते हैं। परीक्षण में कोई बात नहीं है कि is_uploaded_file() यूनिट परीक्षण में काम करता है। यह PHP की ज़िम्मेदारी है, और आप एकीकरण (अंत-टू-एंड) परीक्षण में अपेक्षित सभी कार्यों को सत्यापित कर सकते हैं।

इससे आपके आई/ओ कोड को न्यूनतम से कम करने में कमी आएगी। उस बिंदु पर आप अपने परीक्षण फ़ोल्डर या vfsStream जैसे पैकेज में वास्तविक फ़ाइलों का उपयोग कर सकते हैं।

+0

जबकि मैं आपके अंक से सहमत हूं, जो आम तौर पर अच्छी सलाह है, वे मेरे वास्तविक प्रश्न को संबोधित नहीं करते हैं जो यूनिट परीक्षण फ़ाइल अपलोड के बारे में है। विशेष रूप से 'is_uploaded_file' है, और php: // इनपुट मेरे कोड में विफल हो जाएगा। ऐसा लगता है कि इसका परीक्षण करने का एकमात्र तरीका .phpt फ़ाइलों का उपयोग कर रहा है, क्योंकि is_uploaded_file और php: // इनपुट को तब तक मजाक नहीं किया जा सकता है जब तक मुझे पता चला है। –

+0

मैंने आशा व्यक्त करने के लिए दूसरा-से-अंतिम पैराग्राफ जोड़ा है। मुद्दा यह है कि आप 'is_uploaded_file() 'या' php: // input' का उपयोग नहीं करेंगे। इसके बजाय अपने 'isUploadedFile() 'और' openInputStream() 'विधियों का नकल करें। –

+0

मेरी राय में यूनिट परीक्षण समस्या को हल करने के लिए आपको कार्यान्वयन नहीं बदला जाना चाहिए। :) –