Related to yesterday's question. I implemented the solution proposed by Mehrdad Afshari but this caused another problem.
To recap: I have a class containing a dictionary of Type->IList<Type>
e.g. Cat->{cat1, cat2}, Zebra->{zebra1, zebra2}
where Cat
and Zebra
are subclasses of Animal
. Now Mehrdad proposed the following method to retrieve the all animals of a certain type:
IList<T> GetAnimalsOfType<T>() where T : Animal {
return dictionary[typeof(T)].OfType<T>().ToList();
}
This works but breaks my unit t开发者_Go百科est. The reason is that Animal is an abstract class and so I'm using Rhino Mocks to stub it (using animal = MockRepository.GenerateStub<Animal>();
). My unit test for this class tries to create a new animal and then see if it's included in the dictionary.
zoo.AddAnimal(animal);
IList<Animal> animals= zoo.GetAnimalsOfType<Animal>();
Assert.That(animals[0], Is.EqualTo(animal));
Unfortunately the type of animal created by Rhino Mocks is an animal proxy and I'm asking for Animal, which breaks my test. Any suggestions on how to correct the situation?
Update: thanks to all for the solutions.
You could ask for the specific type you have just inserted. You have to create a helper function:
T Get<T>(T parameterOnlyToInferTheType)
{
IList<Animal> animals= zoo.GetAnimalsOfType<T>();
return animals[0];
}
animal = MockRepository.GenerateStub<Animal>();
zoo.AddAnimal(animal);
Animal expected = Get(animal);
Assert.That(expected, Is.EqualTo(animal));
Looks a bit dodgy still, but should work.
In general I tend to avoid keying collections on type, so I don't have these problems (e.g. I have a property on the class that returns an enum, etc).
As you can't use this due to the compiler needing to know the type in advance:
zoo.AddAnimal(animal);
IList<Animal> animals= zoo.GetAnimalsOfType<typeof(animal)>();
Assert.That(animals[0], Is.EqualTo(animal));
I think you'll have to roll your own mock:
class MockAnimal : Animal
{
}
zoo.AddAnimal(new MockAnimal());
IList<Animal> animals= zoo.GetAnimalsOfType<MockAnimal>();
Assert.That(animals[0], Is.EqualTo(animal));
also do you not want to check that the instance returned is not the same instance that was added, rather than just equal to? (not certain of the syntax, still you the Asset.AreSame() here)
Assert.That(animals[0], Is.SameAs(animal));
Its not surprising the other doesn't as you want the GetAnimalsOfType
to only return animals of the exact type don't you, not types that are derived from that? If you did this:
class Tiger : Animal
{
}
zoo.AddAnimal(new Tiger());
IList<Animal> animals= zoo.GetAnimalsOfType<Animal>();
would you expect this to pass:
Assert.AreEqual(1, animals.Count);
I assume not. If you want to do what you outlined I think you will have to create an actual Animal not a mock.
精彩评论