Code design / testability How?

My team is developing a library that wraps calls to Active Directory to find and return a list of people.

We have a person class that wraps information for the found person. We then use List to collapse them. When we call search, it uses the internal System.Directory library and returns a SearchResultCollection object. We then iterate over it to create a <> list and return that.

We designed the person class for read-only properties (get) as we don't want the caller to change user information. We pass the SearchResult object from the System.Directory library in the human constructor.

My problem is that we cannot verify this easily.

My thoughts so far have been:

  • Pass variables to the person constructor for each property that needs to be set.

    Unfortunately this will lead to a very long list of constructor parameters .... Smells bad to me.

  • Allow the person class to have property settings.

    Again, it smells bad to me since we have no control over the called user.

  • Refactoring:

    I looked at extraction for the interface and adapted the parameter methods. Seems like the adaptation parameter is the most promising? The Adapt parameter looks good because it helps to break the dependency I have on the SearchResult object of the directory library. Therefore, if in the future I want to do another search, we are in good shape. At least I think we are?

  • Subclass the human object class and create a Face test with setters ....

    It looks like it will work, but not sure if this is the right way?

  • Give it up

    Didn't make fun of it, but again I'm not sure about it.

EDIT: If mocking is a better idea, please let me know ... However, I would be interested to know how this could be done without mocking (or perhaps it really is not capable without mocking) ... ...

I would appreciate some guidance on this.

Here's a snippet of code:

    public class PeopleSearcher
{
   .... declarations left out....

    public List<Person> FindPerson(string FirstName, string LastName, string Login)
    {
         ...filter setup left out for brevity....

         _peopleFound = _directoryToSearch.FindAll();
        //Convert to list of persons....
            int cnt = 0;
            _listOfPeople = new List<Person>();
            while (cnt < _peopleFound.Count)
            {
                Person p = new Person(_peopleFound[0]);
                _listOfPeople.Add(p);
                cnt++;
            }
            return _listOfPeople;
        }

    }

    public class Person
    {
        private string sn;
        ....further declarations left out for brevity....

        public Person(SearchResult PersonFound)
        {
            sn = PersonFound.Properties["sn"].Count == 0 ? string.Empty : PersonFound.Properties["sn"][0].ToString();
            givenName = PersonFound.Properties["givenName"].Count == 0 ? string.Empty : PersonFound.Properties["givenName"][0].ToString();
            sAMAccountName = PersonFound.Properties["sAMAccountName"].Count == 0 ? string.Empty : PersonFound.Properties["sAMAccountName"][0].ToString();
            adsPath = PersonFound.Path == null ? string.Empty : PersonFound.Path;

        }

        public string LastName
        {
            get
            {
                return sn;
            }
        }

        .... more getters...
     }
}

      

+2


source to share


3 answers


"Mocking" is a word that is commonly used for all kinds of test doubles . And more often people or not "mocking", they pretend or wrap up. Anyway, your 4th option (subclassing and additional setters) sounds to me like the easiest way your codebase gives, assuming you want Person objects to be passed to other methods. Since I don't think you are talking about testing that the human object gets the properties given by the constructor, right?



+1


source


Excuse me. This is a situation in which they mocked. I've only mocked Ruby, so I'm not sure about the current level of .net, but it should work well.



When you mock it, you can implement some areas that need to be refactored. This is also a good plan.

0


source


In your layout (wireframe or otherwise) you will still have to create Person objects with values, which will lead you to the original problem.

Fortunately, there are two great solutions:

1) Go ahead and add setters to the Person class, but make them protected. This means that your layout and test code should be in the same package, but would block other users from mutating your Faces. (and we don't want mutants to run around - there have been enough of them lately).

2) Use the Builder class (as Joshua Bloch describes in Effective Java). You must create a public static PersonBuilder class inside Person that will export the assembly method and parameter specifiers (e.g. setters, but not separately called):

public class Person ....
   public static class PersonBuilder {
      public PersonBuilder (String firstName, String lastName) {...} // my sample has two required values
      public Person build () {...}
      public PersonBuilder ssn (String value) {...}
      public PersonBuilder adsPath (String value) {...}
      ...
   }
   ...
}

Anchored value specifiers look like this:

      public PersonBuilder ssn (String value) { 
         this.sn = value;
         return this;
      }

Then the call to create Person looks like this:

   Person thisPerson = new Person.PersonBuilder ("John", "Smith"). Ssn ("123-45-6789"). AdsPath ("whatever");

This method completely hides the methods that can set values ​​(indeed, you don't have "setters"), but does not allow you to deal with long lists of constructor arguments (which makes it easier to handle optional values).

By the way, you also probably want to make the Person constructor private.

0


source







All Articles