Given a abstract factory implementation:
public class FooFactory : IFooFactory {
public IFoo Create(object param1, object param2) {
return new Foo(param1, param2);
}
}
What unit tests would be written for this class? How can I verify that param1 and param2 were forwarded to the creation of Foo? Do I have to make these public properties of Foo? Wouldn't that be breaking encapsulation? Or should I leave this to integration testing?
Summary. There are two ways to unit test a class hierarchy and an abstract class: Using a test class per each production class. Using a test class per concrete production class.
There are 2 types of Unit Testing: Manual, and Automated.
Unit Testing Techniques: Black Box Testing - Using which the user interface, input and output are tested. White Box Testing - used to test each one of those functions behaviour is tested. Gray Box Testing - Used to execute tests, risks and assessment methods.
With JUnit, you can write a test class for any source class in your Java project. Even abstract classes, which, as you know, can't be instantiated, but may have constructors for the benefit of “concrete” subclasses.
Here's how I would write one of a couple of unit tests for such a factory (with xUnit.net):
[Fact]
public void CreateReturnsInstanceWithCorrectParam1()
{
var sut = new FooFactory();
var expected = new object();
var actual = sut.Create(expected, new object());
var concrete = Assert.IsAssignableFrom<Foo>(actual);
Assert.Equal(expected, concrete.Object1);
}
Does it break encapsulation? Yes and no... a little bit. Encapsulation is not only about data hiding - more importantly, it's about protecting the invariants of objects.
Let's assume that Foo exposes this public API:
public class Foo : IFoo
{
public Foo(object param1, object param2);
public void MethodDefinedByInterface();
public object Object1 { get; }
}
While the Object1
property slightly violate the Law of Demeter, it doesn't mess with the invariants of the class because it's read-only.
Furthermore, the Object1
property is part of the concrete Foo class - not the IFoo interface:
public interface IFoo
{
void MethodDefinedByInterface();
}
Once you realize that in a loosely coupled API, concrete members are implementation details, such concrete-only read-only properties have a very low impact on encapsulation. Think about it this way:
The public Foo constructor is also a part of the API of the concrete Foo class, so just by inspecting the public API, we learn that param1
and param2
are part of the class. In a sense, this already 'breaks encapsulation', so making each parameter available as read-only properties on the concrete class doesn't change much.
Such properties provide the benefit that we can now unit test the structural shape of the Foo class returned by the factory.
This is much easier than having to repeat a set of behavioral unit tests that, we must assume, already cover the concrete Foo class. It's almost like a logical proof:
Well, presumably those parameters make the returned IFoo
have something true about it. Test for that being true about the returned instance.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With