Setting Up Unit Testing in an Existing Unity Project

Setting Up Unit Testing in an Existing Unity Project

If you’re knee-deep in a Unity project and pulling your hair out trying to set up unit testing, you’re not alone. The two biggest challenges are dealing with Assembly Definitions and Editor folders. Here’s a guide to overcome these issues and make your life easier.

The Problem

Unity, in its infinite wisdom, doesn’t allow writing tests on the default Assembly-CSharp and Assembly-CSharp-Editor assemblies. Frustrating, right?

To fix this, you need to add Assembly Definitions for both your game code and editor code. Here’s how:

Game Code:

Add an Assembly Definition at the root of your project.
Update the dependencies in the Inspector until there are no compiler errors. Off to the races!

Editor Code:

Here’s where it gets tricky. In a big project, you’ll have lots of external dependencies and plugins, some with Assembly Definitions, some without.
Without Assembly Definitions, Unity sees these Editor folders as game code and tries to build them into your final game, which inevitably fails.

The Solution

Create a Top-Level Editor Folder:

At the top level of your project, create an Editor folder.
Add an Assembly Definition inside this folder. Name it similarly to your game code Assembly Definition but with a .Editor postfix (or whatever you prefer).

Link Editor Folders:

For each Editor folder in your project, create an Assembly Definition Reference and link it to the top-level Editor folder Assembly Definition.
This process can be incredibly tedious in a large project, so here’s a Python script to save you from hours of mind-numbing work:

import os
import json
import yaml

def get_guid_from_meta(meta_file_path):
with open(meta_file_path, r) as meta_file:
meta_content = yaml.safe_load(meta_file)
return meta_content.get(guid)

def create_reference_json(editor_path, source_file_name, guid):
json_content = {
reference: GUID: + guid
}
asmref_file_name = os.path.splitext(source_file_name)[0] + .asmref
json_file_path = os.path.join(editor_path, asmref_file_name)
with open(json_file_path, w) as json_file:
json.dump(json_content, json_file, indent=4)
print(fCreated {json_file_path} with GUID reference.)

def copy_file_to_editor_folders(unity_project_path, source_file):
if not os.path.isdir(unity_project_path):
print(fThe project path {unity_project_path} does not exist.)
return

meta_file_path = source_file + .meta
if not os.path.isfile(meta_file_path):
print(fThe meta file {meta_file_path} does not exist.)
return
guid = get_guid_from_meta(meta_file_path)

source_file_name = os.path.basename(source_file)

for root, dirs, files in os.walk(unity_project_path):
if Editor in dirs:
editor_path = os.path.join(root, Editor)
asmdef_exists = any(file.endswith(.asmdef) for file in os.listdir(editor_path))

if not asmdef_exists:
create_reference_json(editor_path, source_file_name, guid)
else:
print(fA .asmdef file already exists in the folder {editor_path}.)

# Example usage
unity_project_path = rPATHTOASSETSFOLDER
source_file = rPATHTOEditor.asmdef

copy_file_to_editor_folders(unity_project_path, source_file)

This script requires pyyaml to run:

pip install pyyaml

Set unity_project_path to your Unity project’s assets folder.
Set source_file to the path of your Editor Assembly Definition.

The script will:

Crawl your project for all Editor folders.
Check if an Assembly Definition is present.
Add an Assembly Definition Reference if none exists.

After setting this up, follow the Unity Testing Framework tutorial to start writing tests.

Additional Tips

Consider splitting your code with Assembly Definitions to create logical boundaries and improve maintainability. It might be a pain now, but your future self will thank you!

Happy developing!

Please follow and like us:
Pin Share