随着我们的工具越来越复杂,我们会需要一些进阶的需求和功能,比如对自己写的工具做单元测试,模拟用户连续但不打断编辑器的操作等等。TAPython的PythonTestLib就是为了给[TAPython的编辑器扩展APIs]做单元测试而开发的
PythonTestLib¶
在PythonTestLib中提供了获取编辑器Log,延迟、重复执行Python命令等功能
Logs¶
获取Output中的Log¶
现在我们可以获取到Output Log中的内容,这样我们就可以用来验证操作的结果,获取Log中警告和错误信息等等
注意,Log和Output Log是不同的,清空Output Log中的Log不会影响PythonTestLib.get_log()返回的内容,反之亦然
清除Log缓冲区¶
当我们不需要之前的log内容的时候,我们可以通过clear_log_buffer()清除缓冲区,这样我们可以在后续的get_logs
中只获取最新的log内容了
在默认情况下,Log缓冲区的大小是10240条log,这个大小可以通过Config.ini中的LogNumberLimit参数来设置。
延迟调用命令¶
TestLib中delay_call与异步定时调用等有一些不同,它是为模拟用户在编辑器中的操作而设计的
主要区别有:
- 主线程执行
和在编辑器中通过Console执行一样,可以获取那些只有在主线程中才能获取的资源。
Extra
和线程相关的内容: PythonBPLib.exec_python_command可以指定是否强制在GameThread中执行Python代码。默认的情况下是在当前线程中执行。例如我们开启了一个线程,然后在这个线程中调用PythonBPLib.exec_python_command,那么这个Python代码就会在这个线程中执行。如果我们想要在GameThread中执行(修改界面内容等必须在GameThread中执行),那么我们可以通过PythonBPLib.exec_python_command中的forece_game_thread参数来指定
- “延迟时间” 等于 “编辑器中的可用时间”
这样我们带代码就不用考虑编辑器实际执行时的卡顿,比如我们在加载地图前push了一个延迟2秒的python调用,那么,不管我们的地图加载了多久。我们的Python代码都会在地图下载完后的2秒时被调用
在 UE_TAPython_Plugin_TestCases@github这个仓库中,有大量的实际案例。
例如下面带代码,我们在加载地图后,等待0.1秒,然后运行我们的测试用例_testcase_get_all_worlds
push_call
是对delay_call
的一个封装,它根据之前累计的延迟时间来计算整体延迟时间,这样我们就不用考虑每次调用的延迟时间了
def test_category_level_actor(self, id:int):
self.test_being(id=id)
# 1
level_path = '/Game/StarterContent/Maps/StarterMap'
self.push_call(py_task(unreal.EditorLevelLibrary.load_level, level_path), delay_seconds=0.1)
self.push_call(py_task(self._testcase_get_all_worlds), delay_seconds=0.5)
self.push_call(py_task(self.check_log_by_str, logs_target=[f"Test Result: StarterMap"]), delay_seconds=0.1)
# 2
self.push_call(py_task(self._testcase_get_all_objects), delay_seconds=0.1)
验证其他数据¶
截取编辑器窗口¶
编辑器中的调试命令:EditorShot
可以截取当前编辑器窗口中显示的内容。我们可以通过这个命令来验证我们的工具是否正确显示了需要的Notification等。
下面这个代码片段,我们在Python中通过execute_console_command
执行了Cmd的调试命令
def editor_snapshot(window_name):
if window_name is None:
print("\tTake editor shot")
unreal.PythonBPLib.execute_console_command(f"EditorShot")
else:
print(f'\tEditorShot Name="{window_name}"')
unreal.PythonBPLib.execute_console_command(f'EditorShot Name="{window_name}"')
TIP
可以通过指定窗口名称,截取指定窗口中的内容。
截取Chameleon窗口¶
对于通过TAPython创建的Chameleon Tool,我们也可以通过unreal.ChameleonData.snapshot_chameleon_window(json_path, override_window_size=override_size)
来截取Chameleon窗口中的内容。这个命令的优点是可以指定窗口的大小,即使窗口中的内容无法完全显示,也可以截取到完整的内容。具体详细信息可见Take UI Snapshot
OCR¶
使用OCR,可以方便得中图片中识别和获取出文本内容。Python中的第三方库有很多,例如在上文提到TestCases中,我使用了easyocr。
使用也很简单:
orc_result = easyocr.Reader(['en'], gpu=False, verbose=False).readtext(image_file_path)