Unit Testing Private Variables

A place to discuss the implementation and style of computer programs.

Moderators: phlip, Moderators General, Prelates

compsciclay
Posts: 1
Joined: Sun Feb 26, 2012 11:07 pm UTC

Unit Testing Private Variables

Postby compsciclay » Sun Feb 26, 2012 11:49 pm UTC

I'm required to implement some unit tests for a team project for my Software Engineering class. We are implementing a game in C# using the XNA framework. I'm new to unit testing and I'm confused about how I should implement a test for several of our class' functions. For instance, we have a function called Movement in our Player class which(you guessed it) handles the main character's movement animations.

Code: Select all

       
private void Movement()
        {
            isMoving = false;
           
            if (keyboardState.IsKeyDown(Keys.Left))
            {
                isMoving = true;
                directionOfMovement = SpriteEffects.FlipHorizontally;
            }
            if (keyboardState.IsKeyDown(Keys.Right))
            {
                isMoving = true;
                directionOfMovement = SpriteEffects.None;
            }

            // If player uses WASD keys to move the sprite
            if (keyboardState.IsKeyDown(Keys.A))
            {
                isMoving = true;
                directionOfMovement = SpriteEffects.FlipHorizontally;
            }
            if (keyboardState.IsKeyDown(Keys.D))
            {
                isMoving = true;
                directionOfMovement = SpriteEffects.None;
            }
        }


How would I go about testing this? Obviously, I want to make sure that isMoving is set to true and that directionOfMovement changes appropriately when specific keys are pressed, but these are both private variables in the class meaning I can't get to them in my unit test. Should I refactor the function to return one of the values? Or perhaps, should I make getters for both variables and access them that way? Either way, it seems to go against good programming practice to make getters or returns that are purely used for testing code, and serve little purpose otherwise.

rflrob
Posts: 235
Joined: Wed Oct 31, 2007 6:45 pm UTC
Location: Berkeley, CA, USA, Terra, Sol
Contact:

Re: Unit Testing Private Variables

Postby rflrob » Mon Feb 27, 2012 2:17 am UTC

I am not a Software Engineer, but my understanding of unit tests is that you want to test behaviors, not implementation. If, once you move your sprite, there's no way for the rest of the program to know whether, how, or where it moved to, then there's nothing to test (and, incidentally, your function could be implemented by simply returning).

Looking at your code, and assuming you're doing something like a Model-View-Controller architecture, you may want to refactor somewhat. As it is, there's quite a bit of overlap between your Player and the keyboard. I'm also guessing that your Player draws itself, rather than letting the Controller ask the Player where it is and which way it's facing, and drawing it appropriately.
Ten is approximately infinity (It's very large)
Ten is approximately zero (It's very small)

User avatar
Jplus
Posts: 1721
Joined: Wed Apr 21, 2010 12:29 pm UTC
Location: Netherlands

Re: Unit Testing Private Variables

Postby Jplus » Mon Feb 27, 2012 3:15 pm UTC

I second the above. Excellent answer from someone who describes themself as "not a software engineer". :)

You can treat implementation details as the insides of a black box, and restrict your unit testing to the outside. Make sure that everything works as you expect, especially all border cases that you can think of. In this case you could run the Movement function and then check that other member functions of the class behave consistenly with the expected state of the private member variables.
"There are only two hard problems in computer science: cache coherence, naming things, and off-by-one errors." (Phil Karlton and Leon Bambrick)

coding and xkcd combined

(Julian/Julian's)

User avatar
freakish777
Posts: 354
Joined: Wed Jul 13, 2011 2:14 pm UTC

Re: Unit Testing Private Variables

Postby freakish777 » Mon Feb 27, 2012 3:59 pm UTC

I suggest looking into the NUnit framework, it gets used a lot in industry.

A quick example, if you have a function:

Code: Select all


float Add(float x, float y)
{
          return x + y;
}



Your unit test is supposed to be an independent validation that that function works. It's been a while since I've written NUnit tests, but I seem to recall that all of your tests are set up essentially to return a Pass/Fail/Unknown/Warning message and you write your tests like:

Code: Select all


NUnitMessage TestAddFunction()
{
       if (Add(1.0, 1.5) != 2.5)
       {
              return NUnitMessage.Fail;
       }
       else
       {
               return NUnitMessage.Pass;
       }     
}



Now, I know the above doesn't seem very useful (because the function I gave is trivial). In your situation, you may want to think about re-writing the Movement function to instead return something (for instance, something that tells you where the Sprite is located in X, Y, Z coordinates after it's moved), so that you have a return value to check against for NUnit testing (also, you may want to make it take input, perhaps a direction, and abstract the KeyPressed Handler to another part of the code that passes W, A, S, D, etc to the right method). Then your Unit tests would set up the objects it needs to run tests, and then run the battery of tests you'd written. Say one of the tests calls your re-written Movement method:

Code: Select all


NUnitMessage TestMoveFunctionWithW()
{
       string xyz = "15x15y0z";
     
       //initialize a new character at the specified coords
       Character myChar = new Character(xyz);

       //add the char to our test world
       World testWorld = new World();
      testWorld.Add(myChar);

       string new XYZ = "";
       try
       {
             newXYZ = myChar.Move("W");
       }
       catch (Exception ex)
       {
            NUnitMessage retVal = NUnitMessage.Unknown;

           retVal.InnerMessage = ex.ToString();

            return retVal;
       }
       
       if (!(yPos(newXYZ) > yPos(xyz))
       {
              return NUnitMessage.Fail;
       }
       else
       {
               return NUnitMessage.Pass;
       }     
}




Personally, I've found unit tests to be extremely useful when you're generating random input to ensure that your function/method doesn't throw unhandled exceptions.

Webzter
Posts: 179
Joined: Tue Dec 04, 2007 4:16 pm UTC
Location: Michigan, USA

Re: Unit Testing Private Variables

Postby Webzter » Mon Feb 27, 2012 5:16 pm UTC

I will third the suggestion to not go about mucking with private methods and private state. Treat it as a black box if at all possible.

That said, if you really get into an instance where you need to go after private state.... you can use reflection (in many cases)

Given a simple class
Spoiler:

Code: Select all

   public class Person
   {
      private string _firstName;
      private string _lastName;

      private string GetName()
      {
         return string.Format("{0} {1}", _firstName, _lastName);
      }
   }


You can use reflection (this is in C# since that's what you posted) to get your stuff.... note, test framework is xUnit.net but the same approach applies no matter

Spoiler:

Code: Select all

   public class When_doing_bad_things
   {
      private Person _personUnderTest = new Person();

      public When_doing_bad_things()
      {
         var firstNameField = typeof(Person).GetField("_firstName", BindingFlags.NonPublic | BindingFlags.Instance);
         var lastNameField = typeof(Person).GetField("_lastName", BindingFlags.NonPublic | BindingFlags.Instance);

         firstNameField.SetValue(_personUnderTest, "Sam");
         lastNameField.SetValue(_personUnderTest, "Iam");
      }

      [Fact]
      public void Can_access_private_state_if_I_really_want_to()
      {
         var firstNameField = typeof(Person).GetField("_firstName", BindingFlags.NonPublic | BindingFlags.Instance);
         var lastNameField = typeof(Person).GetField("_lastName", BindingFlags.NonPublic | BindingFlags.Instance);

         Assert.Equal("Sam", firstNameField.GetValue(_personUnderTest));
         Assert.Equal("Iam", lastNameField.GetValue(_personUnderTest));
      }

      [Fact]
      public void Can_call_a_private_method_if_I_really_want_to()
      {
         var nameMethod = typeof(Person).GetMethod("GetName", BindingFlags.NonPublic | BindingFlags.Instance);

         var result = (string)nameMethod.Invoke(_personUnderTest, null);

         Assert.Equal("Sam Iam", result);
      }
   }


Another approach, which is going to be more amenable to most tool sets, is to introduce a dummy class just for testing:

Spoiler:

Code: Select all

   public class Person
   {
      protected string _firstName;
      protected string _lastName;

      protected string GetName()
      {
         return string.Format("{0} {1}", _firstName, _lastName);
      }
   }

   public class PersonForTest : Person
   {
      public string FirstName { get { return _firstName; } set { _firstName = value; } }
   }


This lets you have fine-grain control over what you expose... and if you change the field on Person from _firstName to _fName (for example) then the second will at least give you a helpful error when you compile. The reflection scenario won't.

Regardless, I agree it's best to treat any need to test private state as a code smell. I think there's already some great advice on what else to think of, so I'm just showing some options for if you really need to go this route (please don't go this route)


Return to “Coding”

Who is online

Users browsing this forum: No registered users and 6 guests