views:

68

answers:

1

i'm trying to test an object by passing a mock owner. Originally PartD would be passed a PartB1 as its owner:

PartD partD = new PartD(partB1);

Now i want to test a feature of PartD by passing it a mock owner:

PartD partD = new PartD(mockPartB1);

This works okay, except there are things PartD does that depends on it knowing some statuses of some of its owners owners:

Boolean PartD.Validate()
{
    //Some fields are not required if the PartA has more than one transaction
    Boolean is24Hour = (this.PartB1.PartA.Transactions.Count > 1);

    if (this.Firstname == "")
    {
       if (!is24Hour)
           LogError("First name is empty");
       else
          LogWarning("First name is empty, but requires reasonable efforts");
    }

    ...
}

This causes my mock object problems because the PartD needs my mock to be of type PartB1, and it needs to implement a property called PartA, which needs to implement a property Transactions, which is a list with a Count.

i'm only interested in testing one part of one method in PartD, so i'm not really interested in re-designing an entire piece of software, surely introducing regressions, so i can test my 2 minute fix. i spent 2 minutes making the fix, and have now lost 6 hours trying to figure out how to test it:

PartD partd = new PartD(mock);
partD.HomeAddress = "123 Maïn Street";

CheckEquals(partD.HomeAddress, "123 Main Street");

Even if i were willing to redesign the entire thing; passing down the TransactionCount to every child object, every time it changes seems like a horrible design. The Validate method, 3 children down, needing to know if there are other transactions isn't the only case in the system of a child needing to have information about its parents.

If the parent objects passed down all this information down to all children, whether they needed it to not, is a waste - and prone to missing an update somewhere.

Also, each time a child-child-child object has a new internal check, it have to re-design all objects around it - so they can all pass down information that may or may not be needed.

How can i avoid children talking to their parents as required, while not having parents giving child objects they don't want?


Edit: The change i'm waiting to test is:

if (Pos(homeAddress, "\r\n") > 0) ...

to

if (Pos("\r\n", homeAddress) > 0) ...
+1  A: 

I think the method probably does need to be rewritten (or at least, refactored a bit); However, if you have control of the partB1 class maybe a quick change that would make it easier to test would be to add a property to partB1 named Is24Hour that returns PartA.Transactions.Count > 1. Then your mock can just return true or false for that particular property.

Obviously this only helps if you have a small number of these deep property accesses.

Chris Shaffer
Logically, the construct makes no sense: A `PartB1` isn't something that is, or is not, "24-hour". It's the `PartA` is logically is 24-hour, by the virtue of it having more than one transaction. But i see how this hack can help me here, now.
Ian Boyd
Nah, i'm not going to do it. The objects are designed right. Passing information down is breaking the encapsulation. i know unit testing, dependency injection and mocks requires breaking encapsulation - but that doesn't mean i have to do it.
Ian Boyd