UE4 自动化测试

我们会从如何调用到执行,整个流程做代码分析:

在游戏开发的时候,我们一般有这样的需求,对我们的代码进行测试。实际上UE4已经有这样的功能了,这样的功能可以参考官网,我这里就不再讲解。

而我现在讲解的是,关于UE4测刷化工具的整体框架分析。

如果我们想做单元测刷 需要将这些内容放在

我们的文件命名规则就是

源文件.spec.cpp


好,现在我们来看看它的框架。我们先举个例子:


BEGIN_DEFINE_SPEC(HelloSpec, "HelloGame.HelloSpec", EAutomationTestFlags::ProductFilter | EAutomationTestFlags::ApplicationContextMask)
TSharedPtr<FAutoGameManage> CustomClass;
FString RunOrder;
END_DEFINE_SPEC(HelloSpec)
void HelloSpec::Define()
{
	//CustomClass = FAutoGameManage::Get();
	////@todo 在此处写下我的期望
	Describe(TEXT("Execute()"), [this]()
		{
			BeforeEach([this]()
			{
				RunOrder = TEXT("A");
			});

			It(TEXT("should return true when successful"), [this]()
			{
				TestTrue(TEXT("Execute"), CustomClass->Execute());
			});

			It(TEXT("should return false when unsuccessful"), [this]()
			{
				TestFalse(TEXT("Execute"), CustomClass->Execute());
			});

			It("will run code before each spec in the Describe and after each spec in the Describe", [this]()
			{
				TestEqual("RunOrder", RunOrder, TEXT("A"));
			});

			AfterEach([this]()
			{
				RunOrder += TEXT("Z");
				TestEqual("RunOrder", RunOrder, TEXT("AZ"));
			});
		});
}

这个用法比较常见,宏的本质就是宏替换,现在我们把这个代码进行拆解,可以看看,它具体可以拆成什么样的代码?

class HelloSpec : public FAutomationSpecBase 
{
public: 
	HelloSpec(const FString& InName) 
	: FAutomationSpecBase(InName, false)
	{
		static_assert((EAutomationTestFlags::ProductFilter | EAutomationTestFlags::ApplicationContextMask)&EAutomationTestFlags::ApplicationContextMask, "AutomationTest has no application flag.  It shouldn't run.  See AutomationTest.h."); 
		static_assert((((EAutomationTestFlags::ProductFilter | EAutomationTestFlags::ApplicationContextMask)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::SmokeFilter) || 
			(((EAutomationTestFlags::ProductFilter | EAutomationTestFlags::ApplicationContextMask)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::EngineFilter) || 
			(((EAutomationTestFlags::ProductFilter | EAutomationTestFlags::ApplicationContextMask)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::ProductFilter) || 
			(((EAutomationTestFlags::ProductFilter | EAutomationTestFlags::ApplicationContextMask)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::PerfFilter) || 
			(((EAutomationTestFlags::ProductFilter | EAutomationTestFlags::ApplicationContextMask)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::StressFilter) || 
			(((EAutomationTestFlags::ProductFilter | EAutomationTestFlags::ApplicationContextMask)&EAutomationTestFlags::FilterMask) == EAutomationTestFlags::NegativeFilter), 
			"All AutomationTests must have exactly 1 filter type specified.  See AutomationTest.h."); 
	} 

	virtual uint32 GetTestFlags() const override { return  EAutomationTestFlags::ProductFilter | EAutomationTestFlags::ApplicationContextMask; }
	using FAutomationSpecBase::GetTestSourceFileName; 
	virtual FString GetTestSourceFileName() const override { return __FILE__; }
	using FAutomationSpecBase::GetTestSourceFileLine; 
	virtual int32 GetTestSourceFileLine() const override { return __LINE__; } 
protected: 
		virtual FString GetBeautifiedTestName() const override { return "HelloGame.HelloSpec"; }
		virtual void Define() override;

	TSharedPtr<FAutoGameManage> CustomClass;
	FString RunOrder;
}; 

namespace
{
	HelloSpec HelloSpecAutomationSpecInstance(TEXT("HelloSpec")); 
}

void HelloSpec::Define()
{
	//CustomClass = FAutoGameManage::Get();
	////@todo 在此处写下我的期望
	Describe(TEXT("Execute()"), [this]()
	{
		BeforeEach([this]()
		{
			RunOrder = TEXT("A");
		});

		It(TEXT("should return true when successful"), [this]()
		{
			TestTrue(TEXT("Execute"), CustomClass->Execute());
		});

		It(TEXT("should return false when unsuccessful"), [this]()
		{
			TestFalse(TEXT("Execute"), CustomClass->Execute());
		});

		It("will run code before each spec in the Describe and after each spec in the Describe", [this]()
		{
			TestEqual("RunOrder", RunOrder, TEXT("A"));
		});

		AfterEach([this]()
		{
			RunOrder += TEXT("Z");
			TestEqual("RunOrder", RunOrder, TEXT("AZ"));
		});
	});
}

我们已经将它编译成功

现在我们打开UE4前端,可以看到我们的单元测试

而其中下面三句对应着我们下面的三句代码

除了这个测试其实还要很多类似的测试方式,我们现在逐一介绍:

1.可定义带成员变量的测试

BEGIN_DEFINE_SPEC(HelloSpec, "HelloGame.HelloSpec", EAutomationTestFlags::ProductFilter | EAutomationTestFlags::ApplicationContextMask)
TSharedPtr<FAutoGameManage> CustomClass;
FString RunOrder;
END_DEFINE_SPEC(HelloSpec)
void HelloSpec::Define()
{
	//测试内容
}

在UE4 里面的效果

2.直接定义测试

DEFINE_SPEC(HelloSpec1, "HelloGame.HelloSpec1", EAutomationTestFlags::ProductFilter | EAutomationTestFlags::ApplicationContextMask)
void HelloSpec1::Define()
{
	Describe(TEXT("Execute()"), [this]()
	{
		BeforeEach([this]()
		{

		});

		It(TEXT("should return true when successful"), [this]()
		{
				//测试内容
		});
			
	});
}

这个实例里面需要加一些内容,如果不加是看不到效果的

3.简洁的测试写法 参数设定为冒烟测试


IMPLEMENT_SIMPLE_AUTOMATION_TEST(HelloSpec2, "HelloGame.HelloSpec2", EAutomationTestFlags::SmokeFilter | EAutomationTestFlags::ApplicationContextMask)
bool HelloSpec2::RunTest(const FString& Parameters)
{
	//这里写测试代码。
	return true;
}

4.NetWork测试

IMPLEMENT_NETWORKED_AUTOMATION_TEST(HelloSpec5, "HelloGame.HelloSpec5", EAutomationTestFlags::PerfFilter | EAutomationTestFlags::ApplicationContextMask,0)
bool HelloSpec5::RunTest(const FString& Parameters)
{
	//这里写测试代码。
	return true;
}

5 除了上面的几个常用的 UE4为我们提供了很多标准的测试方式

发表回复