Bootstrap Chameleon Logo

Test case

随着我们的工具越来越复杂,我们会需要一些进阶的需求和功能,比如对自己写的工具做单元测试,模拟用户连续但不打断编辑器的操作等等。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)
image_name

验证其他数据

截取编辑器窗口

编辑器中的调试命令: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)

参考