53
Thursday, March 18, 2010

Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

  • Upload
    kore-vm

  • View
    1.877

  • Download
    3

Embed Size (px)

Citation preview

Page 1: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Thursday, March 18, 2010

Page 2: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Lua in Testing

Paul Du BoisDouble Fine Productions

Thursday, March 18, 2010

Page 3: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

» Paul: Senior Programmer

» Bert: Software Test Engineer

» RoBert:Robot brainchildAutomated tester

About us

Thursday, March 18, 2010

Page 4: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

120-second pitch

» Unit testing is well understood

» “But how do we test game logic…”

» We implemented a prototype

Thursday, March 18, 2010

Page 5: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

The result

120-second pitch

» Framework for writing very high-level code to exercise game

» Runs on any idle devkit

» Used directly by

❖Test

❖Gameplay, System programmers

❖Designers

Thursday, March 18, 2010

Page 6: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

The result

120-second pitch

» Everyone at Double Fine loves RoBert(even though it gives them bugs)

» Game would be significantly smaller without it

» Permanent part of our process

Thursday, March 18, 2010

Page 7: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

The result

120-second pitch

Demo time!

Thursday, March 18, 2010

Page 8: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Overview of talk

» Motivation

» Implementation

» Uses and examples

Thursday, March 18, 2010

Page 9: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Problem summary

Thursday, March 18, 2010

Page 10: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Problem summary

» Brütal Legend is big

» …big technical challenge

» …big design

» …big landmass

Thursday, March 18, 2010

Page 11: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Problem summary

» Double Fine is small

» Test team is very small

Thursday, March 18, 2010

Page 12: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Implementation¨

Thursday, March 18, 2010

Page 13: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Preëxisting Tech

» Console, networked

» Input abstraction

» Reflection

» Lua 5.1

Thursday, March 18, 2010

Page 14: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Reflection

Entity A02_Headbanger2F3

CoPhysics

Pos: (3,4,5)Mass: 10

CoController

State: Idle

CoDamageable

Health: 30Ragdoll: true

Thursday, March 18, 2010

Page 15: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Reflection

Entity* e = ...;Co* co = e->GetComponent(“CoDamageable”);

Class* cl = co->GetClass();Attribute* a = cl->GetAttribute(“Health”);

Any any = a->GetValueAny(co);float health = any.GetAs<float>();

Thursday, March 18, 2010

Page 16: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Lua implementation

» Class system with inheritance

» Wrapper for Entity instances

» Smidgen of coroutines

» No debugger ☹

Thursday, March 18, 2010

Page 17: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Lua and Tests

» Class system with simple inheritance

» See Programming in Lua § 13.4.1

class = { Run = <function>, Teardown = <function>, bFastSpeed = true}instance = { <mt> = { __index = class }}

Thursday, March 18, 2010

Page 18: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

player.CoDamageable.Health

Lua and Entities

Entity* e = ...;Co* co = e->GetComponent(“CoDamageable”);

Class* cl = co->GetClass();Attribute* a = cl->GetAttribute(“Health”);

Any any = a->GetValueAny(co);float health = any.GetAs<float>();

Thursday, March 18, 2010

Page 19: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Lua and Entities

Entity A02...

CoScript

Table ref: <opaque>

Lua table

_cpp_ref: 0x1ea7f000

player.CoDamageable.Health

Thursday, March 18, 2010

Page 20: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Lua and Entities

player.CoDamageable.Health

player -> { __cpp_ref = 0x1ea7f00, <mt> = ent_mt }

Thursday, March 18, 2010

Page 21: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Lua and Entities

player.CoDamageable.Health

player -> { __cpp_ref = 0x1ea7f00, <mt> = ent_mt }

player.CoDamageable -> { __ent = player, __comp = ‘CoDamageable’, <mt> = comp_mt }

Thursday, March 18, 2010

Page 22: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Lua and Entities

player.CoDamageable.Health

player -> { __cpp_ref = 0x1ea7f00, <mt> = ent_mt }

player.CoDamageable -> { __ent = player, __comp = ‘CoDamageable’, <mt> = comp_mt }

Player.CoDamageable.Health -> 60

Thursday, March 18, 2010

Page 23: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Lua and Entities

» Entity keeps table alive

Entity A02...

CoScript

Table ref: <opaque>

Lua table

_cpp_ref: 0x1ea7f000

Thursday, March 18, 2010

Page 24: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Lua and Entities

» Entity may be deleted at will

» A destructor clears out out _cpp_ref

Entity A02...

CoScript

Table ref: <opaque>

Lua table

_cpp_ref: false

Thursday, March 18, 2010

Page 25: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Lua and Tests

function Class:waitForActiveLine(self, ent) while true do self:sleep(0) if not ent.CoVoice.HasActiveVoiceLine then return end end end

Thursday, March 18, 2010

Page 26: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Lua and Tests

» Test can function as input source

» Mutate a state block

» Use blocking calls to make API convenient

» Manipulate joystick in “world coordinates”

Thursday, March 18, 2010

Page 27: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Example: providing input

-- push some button for time t1

self.input.buttons[btn] = trueself:sleep(t1)self.input.buttons[btn] = false

-- move towards world-space pos x,y,z

self.input.joy1 = test.GetInputDir(x,y,z)

Thursday, March 18, 2010

Page 28: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Example: simple mission

function Class:Run() function fightSpiders(entity) self:attackSmallSpiders() self:killHealerSpiders() self:basicFightFunc(entity)

self:waypointAttack( "P1_050_1", "Monster", 40, fightSpiders) self:attackEntitiesOfTypeInRadius( "Monster", 50, fightSpiders) self:attackBarrier("A_WebBarrierA", 100) self:waypointTo{"P1_050_ChromeWidowLair"}

Thursday, March 18, 2010

Page 29: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Example: reproduce a bug

function Class:Run() function waitForActiveLine() while true do self:sleep(0) if not player.CoVoice.HasActiveVoiceLine then return

streams = sound.GetNumStreams() while true do game.SayLine( 'MIIN001ROAD' ) game.SayLine( 'MIIN001ROAD' ) waitForActiveLine() if sound.GetNumStreams() > streams then self:sleep(1) self:ASSERT(sound.GetNumStreams() <= streams)

Thursday, March 18, 2010

Page 30: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Role of the human

» Bot farm means more time writing bugs

» Half time writing new tests, updating old tests, writing/regressing bugs

» Half time on infrastructure work

Thursday, March 18, 2010

Page 31: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Uses and Examples̊

Thursday, March 18, 2010

Page 32: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Uses and Examples

» Does the game start/quit/leak memory?

» Do these entities spawn properly?

» Can this unit pathfind properly?

Thursday, March 18, 2010

Page 33: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Uses and Examples

» Can player interact with this unit?

» Can bot fly across the world without the game crashing?

» Can I go to each mission contact and talk to them?

Thursday, March 18, 2010

Page 34: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Uses and Examples

» Can I complete each contact's mission?

» Can I successfully fail the mission?

» Multiplayer!

Thursday, March 18, 2010

Page 35: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Diagnostic “tests”

» What is our memory usage as a function of time?

» How does it change from build to build?

» Where are the danger spots?

Thursday, March 18, 2010

Page 36: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Thursday, March 18, 2010

Page 37: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Diagnostic “tests”

» What does our performance look like as a function of time?

» How does it change from build to build?

» What is it like in certain troublesome scenes?

Thursday, March 18, 2010

Page 38: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Thursday, March 18, 2010

Page 39: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Non-test tests

» Reproduce tricky bugs

» Typically involve feedback between test and programming

» Guess at the fail case, try to exercise it

Thursday, March 18, 2010

Page 40: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Use by programmers

» Pre-checkin verification

» Soak testing for risky changes

» Can use Debug builds!

Thursday, March 18, 2010

Page 41: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Thursday, March 18, 2010

Page 42: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Use by designers

» Write a series of balance “tests”

» Throw permutations of unit groups at each other

» Print out results in a structured fashion

» Examined by a human for unexpected results

Thursday, March 18, 2010

Page 43: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Use by artists

» They don’t run it themselves…

» …but they do see it running

» See parts of the game they normally wouldn’t

» Notice things that don’t look right

Thursday, March 18, 2010

Page 44: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Takeaway

» Rapid development: doing a prototype was cheap and low-risk

» Lua doesn’t crash the game

» Coroutines and higher-order functions let you write powerful, concise code

» Performance not an issue

Why was this project successful?

Thursday, March 18, 2010

Page 45: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Fill out forms!

Thursday, March 18, 2010

Page 46: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

‘’Questions?

[email protected]

Thursday, March 18, 2010

Page 47: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Number of bugs found

2006-05-01

2006-09-01

2007-01-01

2007-05-01

2007-09-01

2008-01-01

2008-05-01

2008-09-01

2009-01-01

(to date) 2009-05-01

(projected) 2009-05-01

0 750 1,500 2,250 3,000

bot totalDate through

Thursday, March 18, 2010

Page 48: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Number of bugs found

» Raw bug count undersells RoBert

» Query didn’t catch all RoBert bugs

» Not all problems found get entered

Thursday, March 18, 2010

Page 49: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Types of bugs found

» Almost all crashes and asserts

» Middleware bugs

» Logic bugs manifest as “Bot stuck in mission” failures

» Complementary to bugs found by human testers

Thursday, March 18, 2010

Page 50: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

What we test

» Most tests merely exercise behavior

» Unsuccessful at verifying behavior

» Correctness of test is an issue

Thursday, March 18, 2010

Page 51: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

What we don’t test

» No testing of visuals

» Limited testing of performance

» Specific behaviors, game logic

Thursday, March 18, 2010

Page 52: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Problems and future work

» Big tests can take hours to complete

» Still a lot of human-required work

» Bot cheats a lot

Thursday, March 18, 2010

Page 53: Robotic Testing to the Rescue - Paul Dubois (DoubleFine)

Our takeaway

» Doesn’t replace a test team

» Does take tedious work off their plate

» Hillclimbing development strategy worked well

» Very curious what others are doing!

Thursday, March 18, 2010