1

I'm creating an object pool in AS3 that uses a stack as its base data structure (implemented with a linked list). I'm new to FlexUnit, but I'd really like to have some unit tests for my classes (as testing them in a new project would be cumbersome at best).

I've run into some problems trying to track variables, though, as my class members aren't public; I want to be able to test my private methods that only affect members of the class. (Examples include creation of the list, popping a node off of the stack, pushing a node back onto the stack, etc.)

FlexUnit's practices seem to state that you have a separate test class that runs test methods against your classes. However, these classes won't have access to my private variables, and I don't want to have to create getters and setters just for the unit tests. Is there a way around this? Can test methods be added inside the class itself, Python-style, instead of in a test case class?

I apologize if this has been asked before. I'm new to this; I appreciate your help. Let me know if I need to clarify with code snippets or anything.

Edit: I've realized that my data structure is actually a stack, not just a generic linked list. I've updated the question to reflect this.

2 Answers2

2

Here's a trick I use with the modern unit testing frameworks. With the modern frameworks, you don't have to extend a TestCase-class or a TestSuite-class. This basic thing gives you such a freedom when you have to deal with testing methods or class fields which aren't public.

Here's the trick:

  1. Let's assume this is the class you need to test:

    package com.npacemo.structures {
    
    class Stack 
    {
        public function push(item:Object):void 
        {
        }
    
        public function pop():Object 
        {
        }
    
        protected var top:Object;
    }
    }
    
  2. Your test can inherit the Stack:

    package com.npacemo.structures {
    
    class StackTest extends Stack 
    {    
        [Test] public function 
        should_push_the_item_on_top():void 
        {
            var item:Object = {name: "Item 01"};
            push(item);
            assertThat(top.name, equalsTo("Item 01"));
        }
    }
    }
    

    If you don't like protected you can also use package-access, but make sure the test and the class under test are in the same package.

It's important not to allow your abstraction to leak with getters and setters methods and public field and methods solely for the purpose of testing. On the other hand if the purpose of your class is to be a data structure then getters and setters make perfect sense. Robert C. Martin discusses in detail the dichotomy between data structures and objects.

Vladimir Tsvetkov
  • 2,983
  • 3
  • 26
  • 36
  • I can't believe that I didn't think of this. This really might be the way to go if I can't just place my test methods inline with my class. Tonight, I'll see whether this will work with FlexUnit (I don't think that test cases have required inheritance) and see if it'll work. I'll still have the private variable problem, but I'd rather toggle between protected and private than leak abstraction solely for testing. (Great wording, had to steal it.) Additionally, I think you meant `internal` instead of `package-access`. ;-) –  Nov 01 '11 at 16:36
  • 'Leaky Abstraction' isn't a term I've coined. It's from Joel Spolsky - http://www.joelonsoftware.com/articles/LeakyAbstractions.html – Vladimir Tsvetkov Nov 01 '11 at 17:38
0

If your linked list is going to be at all useful, it will expose some things that will give you access to this information. For instance, in the implementation I posted here http://flexdiary.blogspot.com/2009/12/riadventure-inspiration.html , the list itself isn't really exposed (because a linked list is mainly just its nodes--so to make it more useful, I separated out a cursor that can iterate over the links).

The cursor has an entry point node for the list, so if you wanted you could test that the list has been created by checking for the entry point. But it's passed as a constructor argument, so many people would just take that as read and not bother with a test.

To test that a link has been added at the end, you can iterate to the end and check that the node that is at the end is the one you added (unless your list is circular, in which case you might have a hard time determining that you've reached the end). However, the point of a linked list is that you add links at the point where you are (by setting the nextLink or whatever property of the previous link to the new node--and the previousLink of the old nextLink to the new node if it is linked in both directions), so you might be having this problem because you're trying to create a whole new construct when you're better off just using Array.

Note that if you want to use my implementation, you're welcome to. I wrote it before I started doing TDD, so it has no tests, but I've used it on at least 3 projects now in some form.

Amy Blankenship
  • 6,485
  • 2
  • 22
  • 45
  • Well....the way I've written it, I have a class for my Node objects and I have a factory class that creates and manages the list, which is my Pool object. Only the Pool object should be able to access the actual links; this allows a user to push and pop to the Pool without breaking it (manually setting a link to null, etc). Due to the nature of this pool, I won't need a cursor for iteration, and the list only needs to be singly-linked, so I'll probably end up rolling my own. It's really more of a stack than anything. (It's good practice, too! :D ) –  Nov 01 '11 at 14:36
  • Actually, your comment made me think - this is really a stack, implemented with a singly-linked list. I'll update my question to make it more clear. –  Nov 01 '11 at 14:37
  • Then really all you need is a reference to the last link in the list, and that's really easy to test--is the last thing you put into the pool what you get back when you ask for something from the pool? – Amy Blankenship Nov 01 '11 at 15:27
  • Also, you may want to consider breaking up the architecture further to make it easier to test (which will almost certainly enhance reuse). For instance, you can have a perfectly normal object with public, testable properties and methods that is a private member of your pool (composition over inheritance). – Amy Blankenship Nov 01 '11 at 15:30
  • That's pretty much what I have now, but the nodes don't really have any methods or members. (I'd intended to have objects inherit from that class, but it might be better to define an interface.) I suppose I can just add some dummy values that I can test against, since a rewrite will likely be necessary. However, I'm still not avoiding the problem of unit-testing the values of private members of a class - for instance, pushing an object to the pool will require setting all class members to defaults. I'll still have to write getters and setters for those just to check their values. :-\ –  Nov 01 '11 at 15:54
  • You also may want to look at Mockalate, which I think will extend your Class under the hood, allowing you to unit test protected methods. – Amy Blankenship Nov 01 '11 at 16:29
  • The poolable objects will have a reset method, but doing Asserts for private variables after a reset will still fail due to nonaccess to a private variable. I'll definitely check out Mockalate, though. I really appreciate your input on this - didn't mean to be difficult. :P –  Nov 01 '11 at 16:31
  • Just because you returned the object to the pool doesn't mean you don't still have a reference to it (until you release it). Just sayin' – Amy Blankenship Nov 02 '11 at 01:48