11import unittest
2- import shutil
2+ import tempfile
33from pathlib import Path
4- from utils .audio_generator import list_voices , generate_audio , AUDIO_DIR
4+ from unittest .mock import AsyncMock , patch
5+
6+ from utils .audio_generator import list_voices , generate_audio
57
68class TestAudioGenerator (unittest .IsolatedAsyncioTestCase ):
79 async def test_list_voices (self ):
810 """测试音色获取功能"""
9- voices = await list_voices ()
11+ class FakeVoices :
12+ def find (self , ** kwargs ):
13+ return [{
14+ "ShortName" : "en-US-TestNeural" ,
15+ "Gender" : "Female" ,
16+ "VoiceTag" : {
17+ "ContentCategories" : [],
18+ "VoicePersonalities" : [],
19+ },
20+ }]
21+
22+ async def create_voices ():
23+ return FakeVoices ()
24+
25+ with patch ("utils.audio_generator.VoicesManager.create" , new = create_voices ):
26+ voices = await list_voices ()
27+
1028 self .assertIsInstance (voices , list )
11- self .assertGreater ( len ( voices ), 10 )
29+ self .assertEqual ( voices [ 0 ][ "name" ], "en-US-TestNeural" )
1230
1331 async def test_generate_audio (self ):
1432 """测试音频生成功能"""
15- text_list = ['It is often said that we are what we repeatedly do.' ,
16- 'This simple statement highlights the incredible influence of our daily habits.' ,
17- 'Habits shape our thoughts, guide our actions, and ultimately determine the kind of life we live.' ,
18- 'Whether good or bad, habits are powerful forces that quietly direct our future.' ]
19- voice_name = "en-US-ChristopherNeural"
20- title = "test"
21- audio_dir , filenames , warning_msg = await generate_audio (text_list , voice_name , title )
22- print (audio_dir , filenames , warning_msg )
23-
24- self .assertEqual (len (text_list ), len (filenames ))
25- self .assertEqual (audio_dir , Path (AUDIO_DIR , title ))
26- self .assertTrue (audio_dir .exists ())
27- self .assertEqual (warning_msg , "" )
28- for i , filename in enumerate (filenames ):
29- self .assertTrue (audio_dir .joinpath (filename ).exists ())
30- self .assertEqual (filename .split ("_" )[0 ], str (i + 1 ))
31- self .assertEqual (filename .split ("." )[1 ], "mp3" )
32- self .assertEqual (len (filename .split ("_" )[1 ].split ("." )[0 ]), 32 )
33-
34- # 清理测试目录
35- dir = Path (audio_dir )
36- if dir .exists ():
37- shutil .rmtree (dir )
33+ class FakeCommunicate :
34+ def __init__ (self , text , voice ):
35+ self .text = text
36+
37+ async def save (self , path ):
38+ Path (path ).write_bytes (b"\xff \xf3 \x64 \xc4 " )
39+
40+ text_list = ["First sentence." , "Second sentence." , "Third sentence." ]
41+ with tempfile .TemporaryDirectory () as temp_dir , patch (
42+ "utils.audio_generator.AUDIO_DIR" , Path (temp_dir ) / "audios"
43+ ), patch ("utils.audio_generator.edge_tts.Communicate" , FakeCommunicate ):
44+ audio_dir , filenames , warning_msg = await generate_audio (
45+ text_list , "en-US-TestNeural" , "test"
46+ )
47+
48+ self .assertEqual (len (text_list ), len (filenames ))
49+ self .assertEqual (audio_dir , Path (temp_dir ) / "audios" / "test" )
50+ self .assertTrue (audio_dir .exists ())
51+ self .assertEqual (warning_msg , "" )
52+ for i , filename in enumerate (filenames ):
53+ self .assertIsNotNone (filename )
54+ self .assertTrue (audio_dir .joinpath (filename ).exists ())
55+ self .assertEqual (filename .split ("_" )[0 ], str (i + 1 ))
56+ self .assertEqual (filename .split ("." )[1 ], "mp3" )
57+
58+ async def test_invalid_audio_is_retried_and_keeps_alignment (self ):
59+ attempts = {}
60+
61+ class FakeCommunicate :
62+ def __init__ (self , text , voice ):
63+ self .text = text
64+
65+ async def save (self , path ):
66+ attempts [self .text ] = attempts .get (self .text , 0 ) + 1
67+ if self .text == "retry" and attempts [self .text ] == 1 :
68+ raise RuntimeError ("temporary" )
69+ if self .text == "invalid" :
70+ Path (path ).write_bytes (b"bad!" )
71+ else :
72+ Path (path ).write_bytes (b"\xff \xf3 \x64 \xc4 " )
73+
74+ with tempfile .TemporaryDirectory () as temp_dir , patch (
75+ "utils.audio_generator.AUDIO_DIR" , Path (temp_dir ) / "audios"
76+ ), patch ("utils.audio_generator.edge_tts.Communicate" , FakeCommunicate ), patch (
77+ "utils.audio_generator.asyncio.sleep" , new = AsyncMock ()
78+ ):
79+ audio_dir , filenames , warning_msg = await generate_audio (
80+ ["ok" , "retry" , "invalid" ], "en-US-TestNeural" , "test"
81+ )
82+
83+ self .assertIsNotNone (filenames [0 ])
84+ self .assertIsNotNone (filenames [1 ])
85+ self .assertIsNone (filenames [2 ])
86+ self .assertEqual (attempts ["retry" ], 2 )
87+ self .assertIn ("第 3 个音频生成失败" , warning_msg )
3888
3989if __name__ == "__main__" :
40- unittest .main ()
90+ unittest .main ()
0 commit comments