How do I get my Actor's lifecycle member functions (e.g. BeginPlay) called on World->SpawnActor in simple Unit Test

Hello,

I have relatively simple ActorComponent class that registers itself with a mult-cast delegate on a GameInstanceSubsystem in its BeginPlay member function.

I am trying to write a small unit test to ensure the correct behaviour, however I am finding it really difficult to get a World and GameInstance setup and running in my test such that the Actor’s lifecycle methods are called when it is spawned.

I have simplified the issue down to just an Actor in order to raise this question. With the code outlined below, it all works as expected when setup in the editor, however the the test fails because the the Actor’s BeginPlay member function is never called, so it never registers itself as a delegate.

Please could someone advise on what else needs to be set up in the test for the BeginPlay member to be called?

I know I could do this in a Automated Functional test, however that seems like quite a lot of overhead for such seemingly simple simple test. Plus, I’d ideally prefer to keep everything in code where I can.

SomeSubsystem.h:

#pragma once

#include "CoreMinimal.h"
#include "SomeSubsystem.generated.h"


DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FComponentsDelegate, int, Value);

UCLASS()
class TESTINGPROJECT_API USomeSubsystem : public UGameInstanceSubsystem
{
	GENERATED_BODY()

public:
	UPROPERTY(BlueprintCallable)
	FComponentsDelegate ComponentsDelegate;
};

SomeActor.h

#pragma once

#include "CoreMinimal.h"
#include "SomeActor.generated.h"


UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class TESTINGPROJECT_API ASomeActor : public AActor
{
	GENERATED_BODY()

public:
	int GetCount() const { return Count; }

protected:
	virtual void BeginPlay() override;

private:
	UFUNCTION()
	void BumpCount(int Increase);
	
	UPROPERTY(VisibleAnywhere)
	int Count = 0;
};

SomeActor.cpp

#include "SomeActor.h"

#include "SomeSubsystem.h"

void ASomeActor::BeginPlay()
{
	Super::BeginPlay();
	UE_LOG(LogTemp, Log, TEXT("Registered with Some Subsystem"))
	GetWorld()->GetGameInstance()->GetSubsystem<USomeSubsystem>()->ComponentsDelegate.AddDynamic(this, &ASomeActor::BumpCount);
	UE_LOG(LogTemp, Log, TEXT("Registered with Some Subsystem"))
}

void ASomeActor::BumpCount(int Increase)
{
	UE_LOG(LogTemp, Log, TEXT("Updating count"))
	Count += Increase;
}

SomeActorTest.cpp

#include "Misc/AutomationTest.h"
#include "TestingProject/SomeActor.h"
#include "TestingProject/SomeSubsystem.h"
#include "Tests/AutomationEditorCommon.h"

IMPLEMENT_SIMPLE_AUTOMATION_TEST(SomeActorTest, "Test.SomeComponentUpdateTest",
                                 EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)

bool SomeActorTest::RunTest(const FString& Parameters)
{
	UGameInstance *GameInstance = NewObject<UGameInstance>();
	GameInstance->Init();
	
	UWorld *World = FAutomationEditorCommonUtils::CreateNewMap();
	World->SetGameInstance(GameInstance);

	const ASomeActor *Actor = World->SpawnActor<ASomeActor>();

	TestEqual("Actor starts with count of 0", Actor->GetCount(), 0);

	World->GetGameInstance()->GetSubsystem<USomeSubsystem>()->ComponentsDelegate.Broadcast(20);

	TestEqual("Actor increase count by 20 after subsystem broadcasts", Actor->GetCount(), 20);
	
	return true;
}

Try to call DispatchBeginPlay on this actor, but make sure this actor has assigned world (Added to the existing world)

Thank you very much for the response, that definitely gets me a passing test!

Whilst this does get me closer to my goal it wasn’t exactly what I was looking for, but that’s on my for not being clear in the original question.

I was hoping to find a way to setup the World such that when I call SpawnActor it calls all of the expected member functions as per the Actor Lifecycle defined here: Actor Lifecycle | Unreal Engine Documentation

Is there anyway to do that?

EDIT: I have updated the original post to hopefully make the above a little clearer.

Have you tried to call BeginPlay on World itself?