
測試文件到底怎么生成這里我摸索出了一套完整方案。尤其是需要可播放的視頻或可正常顯示的圖片時不能簡單拿隨機字節(jié)去填充里面有不少細節(jié)坑。之所以想寫這篇是因為上周幫別人搞一個上傳接口的壓測對方給的需求只有一句給我準備幾個10MB、50MB的文件。我隨手在Linux上敲了dd if/dev/zero oftest.bin bs1M count10生成了10MB文件。結果文件丟給開發(fā)后對方說上傳到系統(tǒng)里被格式校驗攔住了——因為服務端只接收圖片或視頻而那個10MB文件只是一堆零字節(jié)。后來又試過在某在線工具網站生成測試視頻下載下來用播放器打開直接報錯因為那些工具生成的視頻只有文件頭是視頻格式實際內容根本不是完整可解碼的。從那次之后我就整理了一套自己的方案適用于Linux、macOS、Windows覆蓋普通文件、可播放視頻、可顯示圖片三類測試素材。這套方案適合誰用后端接口測試、App測試、運維需要驗證CDN傳輸或者前端要測試上傳控件都很適合。下文所有命令我都給到了可以直接復制運行的級別。1. 測試場景里最常被忽略的痛點文件能用比夠大更重要很多測試工具教程會讓用戶在Linux上用dd或fallocate生成一個大文件然后直接拿去做上傳測試。這個思路本身沒錯但有一個隱藏前提被測系統(tǒng)如果只是把文件當作二進制流轉發(fā)或存儲那么全零文件完全夠用??梢坏┫到y(tǒng)加了任何內容識別邏輯哪怕是讀一下文件頭或MIME類型全零文件就會當場露餡。我實際遇到過的幾種典型場景你可以對照判斷自己的需求屬于哪一類后端接口接收文件后調用圖片處理服務如縮略圖、水印如果是損壞圖片服務直接報500視頻平臺上傳接口會做預解析讀取時長、分辨率、編碼格式假視頻文件無法通過CDN上傳壓測時雖然不關心內容但如果有邊緣節(jié)點做了Content-Type探測全零文件會引起不可預料的失敗前端Web頁面上傳組件用FileReader讀取文件并預覽全零文件在瀏覽器里無法以img或video標簽展示。所以說在準備測試素材時第一步是搞清楚被測系統(tǒng)對文件內容有沒有格式要求。如果只是驗證文件大小限制這個邏輯本身用dd生成普通文件就夠了如果需要走完整業(yè)務鏈路那就要生成內容真實可用的文件。下文第2、3、4節(jié)會分別講清這三類文件的生成方式。2. 通用文件怎么生成三行命令解決80%的臨時需求先講最基礎的——生成一個不關心內容、只關心字節(jié)大小的通用文件。這類文件適合測試文件上傳大小限制、網絡帶寬、下載速度、存儲容量等場景。2.1 dd命令可控性最強的基礎工具dd是Linux/macOS下最通用的方式。它的參數(shù)核心是bs和count兩者相乘就是最終文件大小。例如要生成10MB這里按十進制含義的MB理解命令中的M通常表示1024×1024字節(jié)dd if/dev/zero oftest_10M.bin bs1M count10執(zhí)行完ls -l test_10M.bin就能看到大小正好是10485760字節(jié)。如果有精確到字節(jié)的需求比如1025字節(jié)這種奇數(shù)大小可以用truncate先建文件再修正或者直接把bs1 count1025。但bs1 count1025這種寫法執(zhí)行很慢每次只寫1字節(jié)我一般這樣處理# 先按較快的塊大小生成 dd if/dev/zero oftest.bin bs1K count1 # 再用 truncate 精確擴展到 1025 字節(jié) truncate -s 1025 test.bintruncate可以任意擴大或縮小文件到指定大小而且速度極快??s小時會截斷內容擴大時補零非常適合我要一個N字節(jié)文件的場景。2.2 truncate秒建超大稀疏文件truncate最強大的地方是生成超大文件幾乎不占磁盤空間。例如truncate -s 10G test_10G.bin執(zhí)行后文件名義大小是10GB但使用du -h test_10G.bin查看會發(fā)現(xiàn)它只占用了極小的磁盤空間。這種文件叫稀疏文件sparse file文件系統(tǒng)不會為這些零字節(jié)區(qū)域分配實際磁盤塊。這個特性在測試中是把雙刃劍。驗證上傳限制時服務器讀取文件時看到的就是0字節(jié)塊這在多數(shù)Linux服務端沒有問題。但如果被測系統(tǒng)會對文件做md5計算或完整性比對稀疏文件的全零內容就會造成誤導——所有同大小的稀疏文件內容完全一樣根本無法區(qū)分你傳的是哪一個。2.3 Windows下用fsutil生成測試文件Windows環(huán)境下沒有直接的dd命令除非裝了GNU工具或WSL但系統(tǒng)自帶的fsutil可以完成同樣的事fsutil file createnew C:\temp\test_10M.bin 10485760數(shù)字單位是字節(jié)所以10MB要寫成10485760。需要注意的是fsutil在某些精簡版Windows上不可用或者權限不足時會報錯。如果你更習慣PowerShell也可以用 .NET 的File.WriteAllBytes配合字節(jié)數(shù)組初始化[System.IO.File]::WriteAllBytes(C:\temp\test_10M.bin, New-Object byte[] 10485760)2.4 全零文件與隨機內容文件怎么選如果被測系統(tǒng)會計算文件指紋或做內容比對建議讓文件內容隨機化。Linux下可以用head -c 10M /dev/urandom test_rand_10M.bin但這種方式生成速度比dd全零慢很多10MB還好1GB以上會明顯等很久。如果是大文件且需要隨機內容可以折中用dd生成全零主體再用隨機數(shù)據(jù)覆蓋文件頭部幾百KB。這樣既能保證文件有大半的隨機特征生成速度也可控。3. 生成可播放的指定大小視頻先用公式算碼率再交給FFmpeg大部分測試教程講到這里就停了但這恰恰是測試素材準備中最關鍵的分水嶺。可播放視頻不能靠堆字節(jié)實現(xiàn)必須用編碼器真正生成畫面和音頻而這兩者的配比直接決定最終文件大小。3.1 理解視頻大小和碼率的數(shù)學關系視頻文件大小的核心公式是文件大小(字節(jié)) ≈ (視頻碼率 音頻碼率) × 時長(秒) / 8注意這里的碼率單位是bpsbit per second而我們平時說的文件大小是字節(jié)所以要除以8。有了這個公式就能反過來根據(jù)目標大小和目標時長算出需要設定的視頻碼率。舉個例子我想生成一個約10MB、時長10秒的MP4文件。假設音頻用128kbps那么視頻碼率可以這樣估算總碼率 10 × 1024 × 1024 × 8 / 10 8388608 bps ≈ 8.39 Mbps減去音頻的128kbps視頻碼率大約取8.2 Mbps。由于編碼器實際輸出會有波動這個數(shù)值算出來后會落在大約10MB附近而不是分毫不差的10485760字節(jié)。這里有個很重要的認知視頻編碼時最終文件大小不可能精確控制到個位字節(jié)。碼率控制本質上是編碼器在盡量貼近目標和保證畫質穩(wěn)定之間折中。對測試場景來說±5%的誤差完全夠用。3.2 固定碼率法用FFmpeg一步到位FFmpeg提供了-b:v視頻碼率、-maxrate最大碼率、-bufsize解碼器緩沖區(qū)大小這幾個參數(shù)。只設置-b:v時編碼器在畫面復雜時會拉高碼率畫面簡單時會降低碼率最終文件大小并不穩(wěn)定。為了更接近目標我習慣同時設置-maxrate和-bufsizeffmpeg -f lavfi -i testsrcduration10:size1280x720:rate30 \ -f lavfi -i anullsrcr44100:clstereo \ -c:v libx264 -b:v 8M -maxrate 8M -bufsize 16M \ -c:a aac -b:a 128k \ -y test_10M.mp4解釋一下這里的幾個要點-f lavfi -i testsrcduration10:size1280x720:rate30這是FFmpeg內置的測試視頻源會生成一段動態(tài)變化的彩色測試圖案且?guī)в袝r鐘時間在播放器里能明顯看到畫面在動-f lavfi -i anullsrcr44100:clstereo生成一段靜音音頻。之所以要加音軌是因為很多播放器和服務端解析器會要求文件至少包含視頻流或音頻流有音軌能提高通用性也更接近真實用戶上傳的文件-c:v libx264 -b:v 8M -maxrate 8M -bufsize 16M視頻采用H.264編碼目標碼率8Mbps。bufsize一般設為碼率的2倍給編碼器一個合理的緩沖窗口-c:a aac -b:a 128k音頻采用AAC編碼碼率128kbps。執(zhí)行完用ffprobe驗證一下文件ffprobe test_10M.mp4可以看到時長、編碼格式、流信息等元數(shù)據(jù)。也可以用播放器打開確認畫面真的在動而不是一張靜止圖。3.3 用不同測試源控制畫面復雜度它直接決定文件大小誤差testsrc是最常用的測試圖案但它的畫面相對平滑壓縮率高這意味著實際文件往往比估算值小一些。如果想讓文件更貼近目標大小可以換成mandelbrot分形圖案或cellauto元胞自動機這類高復雜度畫面ffmpeg -f lavfi -i mandelbrotsize1280x720:rate30:end_pts300 \ -f lavfi -i anullsrcr44100:clstereo \ -c:v libx264 -b:v 8M -maxrate 8M -bufsize 16M \ -c:a aac -b:a 128k \ -y test_mandelbrot_10M.mp4高復雜度畫面不容易被壓縮編碼器需要花更多碼率去保留細節(jié)最終文件大小會更貼近甚至略超目標值。實測對比下來同樣的碼率設置mandelbrot產物比testsrc大30%左右。理解了這條規(guī)律之后你就能根據(jù)測試需求反向選擇測試源測試源畫面復雜度實際文件大小相對目標的趨勢適用場景testsrc中等偏低偏小通用測試、快速生成rgbtestsrc顏色漸變平滑更小需要色彩參考的測試smptebarsSMPTE彩條界面分明偏小兼容性、色彩還原測試mandelbrot高偏貼目標需要精確逼近目標體積cellauto高偏貼目標需要高隨機性畫面的場景順帶提一句如果你的測試場景要求視頻分辨率是4K、或者編碼格式是HEVCH.265把size改為3840x2160、把編碼器從libx264換成libx265即可。H.265的壓縮率更高同樣碼率下文件更小。3.4 生成超大視頻時先想清楚組合策略生成100MB以上視頻時如果還死磕高碼率短視頻的組合會遇到一個瓶頸碼率超過一定程度后編碼器也要保持輸出但畫面復雜度撐不住高碼率文件大小依然上不去。我在實測里發(fā)現(xiàn)生成100MB視頻用時10秒需要約84Mbps的碼率這遠超常規(guī)視頻碼率某些編碼器會表現(xiàn)不穩(wěn)。更靠譜的做法是延長時長。生成一個60秒、目標碼率約14Mbps的視頻文件大約105MB這個碼率在H.264編碼下更自然文件也不容易因為編碼器限制而產生大的偏差。ffmpeg -f lavfi -i smptebarsduration60:size1920x1080:rate30 \ -f lavfi -i anullsrcr44100:clstereo \ -c:v libx264 -b:v 13853k -maxrate 13853k -bufsize 27706k \ -c:a aac -b:a 128k \ -y test_100M.mp4這里我就不手動算碼率了直接把公式帶入目標100MB時長60秒(100×1024×1024×8/60) 約等于13.98Mbps減掉0.128Mbps的音頻視頻碼率取13853kbps左右。生成后一般會在95~110MB之間對測試來說足夠精確。4. 生成看起來真實的指定大小圖片按尺寸和按大小是兩條路線圖片和視頻不同視頻靠碼率×時長控制大小圖片最大的影響因素是分辨率和內容復雜度。所以生成指定大小的圖片要先搞清楚指定大小指的是分辨率還是字節(jié)數(shù)——兩者經常被混為一談。4.1 按像素尺寸生成用ImageMagick最快如果測試只要求一張1920x1080的圖片不關心字節(jié)數(shù)那用ImageMagick的convert命令最省事# 生成純色漸變圖 convert -size 1920x1080 gradient:blue-yellow test_gradient.png # 生成噪聲紋理圖plasma是ImageMagick內置的復雜紋理 convert -size 1920x1080 plasma:fractal test_plasma.pnggradient生成的是一張平滑漸變圖色彩過渡自然在瀏覽器和系統(tǒng)看圖器里都能正常打開plasma:fractal生成的是一張類似火星表面或流體效果的紋理圖視覺上更豐富但由于細節(jié)多文件也更大。如果你是Python技術棧不想依賴ImageMagickPillow可以做到同樣的事from PIL import Image img Image.new(RGB, (1920, 1080), (30, 144, 255)) img.save(test_blue_1920x1080.png) # 生成橫向漸變 pixels img.load() for x in range(1920): for y in range(1080): pixels[x, y] (int(x / 1920 * 255), 100, 200) img.save(test_gradient_1920x1080.png)但注意Pillow逐像素操作大圖時速度很慢測試素材不需要逐像素定制所以更推薦用ImageMagick的一行命令。4.2 按文件大小生成隨機噪聲圖是最直接的辦法如果需求是給我一張5MB左右的JPEG圖片這就要走上按字節(jié)控制圖片大小的路子。核心思路很簡單圖片之所以小是因為大面積顏色區(qū)域可以被壓縮得很高效反過來圖片里全是隨機噪點壓縮算法就很難縮小體積文件就會逼近像素數(shù)據(jù)的原始大小。用Python Pillow生成隨機噪點圖from PIL import Image import numpy as np width, height 1920, 1080 arr np.random.randint(0, 255, (height, width, 3), dtypenp.uint8) Image.fromarray(arr).save(test_noise.png)生成出來的PNG通常非常大因為隨機RGB數(shù)據(jù)壓縮率極低。但沒有numpy時用純Python逐像素填充太慢所以我還是建議直接上numpy。如果環(huán)境里不能用numpy退而求其次可以用ImageMagickconvert -size 1920x1080 xc: noise Random test_noise.png同樣能生成隨機噪點圖。這套思路能幫你快速估算像素數(shù)和最終文件大小的關系。一張RGB隨機噪點圖片的PNG大小約等于寬×高×3字節(jié)再加上PNG容器的幾十KB開銷。所以想生成約10MB的PNG需要約1000萬像素——正好接近一個3000x3000的圖。經驗做法是把目標像素數(shù)乘以0.98作為實際寬高積給PNG元數(shù)據(jù)留一點余量。4.3 用JPEG質量參數(shù)逼近目標大小JPEG是有損壓縮格式文件大小不僅僅取決于分辨率還取決于壓縮質量。如果目標大小不是恰好10000KB而是大約5MB、允許誤差500KB那用質量參數(shù)慢慢逼近是很快的。我用過一個簡單腳本效果不錯from PIL import Image import numpy as np # 生成隨機噪點圖作為基礎 arr np.random.randint(0, 255, (2000, 2000, 3), dtypenp.uint8) img Image.fromarray(arr) # 從質量85開始逐個質量值試直到接近目標大小 target 5 * 1024 * 1024 for quality in range(95, 50, -5): img.save(approx_5M.jpg, qualityquality) if Path(approx_5M.jpg).stat().st_size target: breakJPEG對隨機噪點的壓縮能力有限質量從95降到60時文件大小不會有特別劇烈的變化但通過微調分辨率和質量把最終大小控制在目標值的5%以內并不難。另外還有一個工具型方案用ImageMagick配合壓縮質量的參數(shù)# 先把圖放大到目標近似尺寸再用質量參數(shù)微調 convert -size 3000x3000 plasma:fractal -quality 85 approx_5M.jpg生成后再看實際大小偏大就降低quality偏小就提高quality或把像素尺寸改大。反復兩次就能貼進目標區(qū)間。4.4 補充PNG與JPEG的壓縮特性差異決定了選型PNG是無損壓縮對漸變、純色區(qū)域壓縮很好對隨機噪點幾乎壓不動JPEG是有損壓縮對噪點會做一部分有損處理但面對隨機高頻信息仍然無法有效壓縮。所以想要盡量接近目標字節(jié)數(shù)偏大方向用隨機噪點PNG因為壓縮率可預測、穩(wěn)定想要能壓縮到目標大小且視覺上像真實照片用 plasma:fractal 或實際照片素材轉JPEG用質量參數(shù)逼近想要一張極小但尺寸很大的圖用純色PNG或JPEG1920x1080的純白JPEG可能只有幾十KB。要根據(jù)最終目的去選而不是一味追求大文件或小文件。5. 落到真實測試場景上傳限制、CDN傳輸和批量文件的實操生成了文件接下來才是重頭戲——怎么用它們完成測試。這節(jié)講幾種最常見的落地場景。5.1 驗證Nginx和Spring Boot的文件大小限制排查Nginx上傳限制時系統(tǒng)最常遇到的行為是請求直接被拒返回413Request Entity Too Large。要復現(xiàn)這個場景只需要生成一個剛好超過限制值的文件然后用curl上傳# 假設Nginx配置了 client_max_body_size 10m curl -F filetest_11M.mp4 http://localhost/upload -v如果看到HTTP/1.1 413 Request Entity Too Large說明上傳大小限制已經生效。此時對比一下9MB、10MB、11MB三個文件就能確認限制值是否精準。Spring Boot項目則是在application.yml里配置了spring.servlet.multipart.max-file-size: 10MB此時傳一個略超10MB的文件后端會拋出MaxUploadSizeExceededException。我實際排查時發(fā)現(xiàn)不同版本的Spring Boot對超限請求的響應碼不一樣有的是400有的是500這個不建議直接當作預期先抓包看真實返回再定斷言。5.2 用一個可播放視頻驗證CDN或對象存儲的上傳鏈路有一次測CDN回源我用dd生成了一堆隨機文件結果上傳是成功了但每次回源拉取的文件在視頻播放器里都沒法打開。排查后發(fā)現(xiàn)CDN邊緣節(jié)點檢查了視頻文件的moov atomMP4文件的索引區(qū)發(fā)現(xiàn)文件里根本沒有這個結構直接判定為無效文件。用FFmpeg生成的視頻文件天然帶完整MP4結構上傳后從CDN節(jié)點拉下來用ffprobe驗證能正常解析出編碼信息才說明鏈路沒有在中間環(huán)節(jié)破壞文件。這是我改成用FFmpeg生成視頻做測試的最大原因。5.3 批量生成不同大小素材的腳本建議測試中往往需要一組遞進大小的文件手工逐條執(zhí)行命令很煩。我通常會寫一個簡單循環(huán)腳本把常用尺寸一次性生成出來for size in 1 5 10 20 50 100; do ffmpeg -f lavfi -i testsrcduration30:size1280x720:rate30 \ -f lavfi -i anullsrcr44100:clstereo \ -c:v libx264 -b:v ${size}M -maxrate ${size}M -bufsize $((size*2))M \ -c:a aac -b:a 128k \ -y test_${size}M.mp4 done圖片類也可以用同樣思路循環(huán)調用ImageMagick。這套腳本我會用目錄結構區(qū)分類型命名里帶上大小和格式方便后面寫自動化測試用例時直接引用路徑。6. 生成過程中繞不開的坑文件系統(tǒng)、編碼器和格式校驗這部分是真正花時間踩過才會知道的經驗。給大家拆幾個印象深刻的坑提前避開。6.1 稀疏文件 vs 實際占用空間別讓假象干擾判斷truncate -s 1G test.bin執(zhí)行后ls -l顯示1GB但du -h test.bin可能顯示只有1MB甚至0。這在測試磁盤滿、分片傳輸這種場景時會造成誤判。系統(tǒng)按名義大小接收文件但文件內容在真正寫入磁盤時如果觸發(fā)了稀疏復制某些服務端工具在計算流量或做存儲空間統(tǒng)計時會看到完全不同的數(shù)值。如果測試目標涉及實際占用空間用dd而不是truncate生成文件更穩(wěn)妥。6.2 文件系統(tǒng)塊大小NTFS/exFAT的意外偏差NTFS和exFAT文件系統(tǒng)對文件分配空間的粒度是簇通常4KB或更大。生成一個1字節(jié)的文件磁盤上占用的是4KB但文件系統(tǒng)把文件大小正確記錄為1字節(jié)。這個差異和稀疏文件是兩回事——文件大小邏輯大小永遠精確占用空間分配大小取決于簇大小。做存儲測試時這兩個指標很容易搞混要看清測試需求問的是哪一個。6.3 擴展名和MIME類型很多系統(tǒng)都認這套表面功夫用FFmpeg生成的是MP4容器即使把文件名改成.mkv或.avi文件內部仍然是H.264AAC的MP4結構。這類改擴展名的文件在服務端做MIME探測時依然能識別為視頻但在嚴格校驗擴展名和內容是否匹配的系統(tǒng)里會被拒收。圖片同理改了擴展名的PNG在服務端強制做JPEG解碼時會失敗。所以在生成素材時擴展名必須與容器格式保持一致。另外Web系統(tǒng)里有一個常被忽略的點服務端不只看文件擴展名還看請求頭里的Content-Type。curl默認會用文件擴展名推斷MIME類型但一些測試工具或代碼庫會固定傳application/octet-stream這會導致上傳組件在瀏覽器預覽時無能為力。6.4 編碼器兼容性FFmpeg不一定自帶libx264有些精簡版FFmpeg或靜態(tài)編譯版本沒打包libx264執(zhí)行上面帶-c:v libx264的命令會直接報Unknown encoder。確認方法ffmpeg -encoders | grep libx264如果沒有可以考慮用內置的mpeg4編碼器代替它兼容性好、各種播放器基本都支持缺點是壓縮率和畫質不如H.264。測試場景里如果對存儲體積不敏感用-c:v mpeg4反而能更快生成文件。6.5 生成完一定要驗證別讓文件看著在但打不開我見過太多人生成測試文件后不做驗證等到測試用例跑掛才回頭查。最有效的驗證方式就兩條視頻用ffprobe看流信息能解析出視頻流、音頻流、時長、分辨率才算通過圖片直接用file命令看實際格式或用Python Pillow重新打開一層確認能正常解碼。養(yǎng)成這個習慣之后我基本沒有因為測試素材本身的問題返工過。尤其是批量腳本運行時加一個循環(huán)檢查5秒鐘的事能省后面很多排查時間。做測試素材這件事看起來簡單但真要做到生成真實內容、結構完整、大小可控、批量可用還是需要一套稍微完整的方案。我實際使用下來普通文件靠dd和fsutil視頻靠FFmpeg碼率公式圖片靠隨機噪點或ImageMagick紋理三套方案交叉覆蓋了絕大多數(shù)測試需求。如果你經常要幫別人準備這類素材建議把這些命令整理成腳本配合命名規(guī)范放在本地用的時候改幾個參數(shù)就行。