0

I came across a situation I don't really know how to solve. I've just created a class Foo that contains a static factory method to create class Bar using some arguments so Foo is kind of a factory class. Now I want to test this method but the problem is, these arguments are modified internally to create the variables needed to call constructor on Bar. As part of the test, I can test I get the final object of Bar but I don't know how to verify the arguments passed to the constructor.

public class Foo {
      public Bar createBarOf(String argumentOne, String argumentTwo) {
             String argumentForBar = argumentOne + argumentTwo;
             return new Bar(argumentForBar);
      }
}

Any suggestions?

EDIT

To make the question more clear, this is the Bar class.

    public class Bar {
          private final String SUFFIX = "BarSuffix";
          private String field;

          public Bar(String argumentForBar) {
                field = argumentForBar + BAR_SUFFIX;
          }
    }

So, having that constructor in mind. When I test createBarFor(argumentOne,argumentTwo) in Foo, I can't figure out how to test that argumentOne and argumentTwo were used to create Bar unless I also test Bar constructor inside that test and assume what the internals of Bar are. argumentOne and argumentTwo are not stored fields of Bar but rather variables to calculate the value of a field in the object.

Juan Vega
  • 1,030
  • 1
  • 16
  • 32

2 Answers2

2

Simply use createBarOf and assert your expectations against the returned Bar object. You should not be trying to assert that ab is passed to the constructor when you create it with arguments a and b, that is contained already when you get the Bar object.

Since there is no exiting logic (execution branches that return from the method) inside createBarOf, you don't have to test anything about this method specifically.

Jeroen Vannevel
  • 43,651
  • 22
  • 107
  • 170
  • 1
    But shouldn't I test my expectations in a specific unit test for Bar class? Testing Bar as part of the test for Foo would make redundant a unit test for Bar (at least for its constructor). I can just test factory method and Bar constructor here but it would seem weird that the unit test for Bar doesn't include a test for its constructor. And just testing that I get an object of type Bar from the factory method wouldn't ensure the logic that creates the argument for the constructor (the actual code is a bit more complicated than concat two strings) – Juan Vega Apr 16 '15 at 12:47
  • @Kilian: I didn't mean that you test that you receive a Bar object. I meant that you perform your assertions on that returned Bar object; What does that argument has as an effect? Does it change some variable? Then assert on `Bar.getArgument()`. Your unit test can comprise multiple layered units: take a look at my answer http://stackoverflow.com/a/17731324/1864167. – Jeroen Vannevel Apr 16 '15 at 13:00
  • 1
    The problem I have is that the argument passed is never stored in the Bar object. It is used inside the constructor to populate a list of other objects. There my problem, there is no `Bar.getArgumentForBar()` but `Bar.getNewCalculatedValue()` . If I want to validate that Foo factory method uses the arguments passed, unless there is a way to catch these arguments in the unit test, I would have to also test the constructor logic in Bar, which I would like to do in a unit test specific for it. – Juan Vega Apr 16 '15 at 14:19
  • You're looking for a much too direct result and I can't make it clearer because your question is too abstract. When you pass in "a" and "b" this has an effect on your construction of Bar, right? Verify this eventual effect with an assert. I suggest you also take a look at [my blog](http://www.vannevel.net/2015/03/31/introduction-to-unit-testing-what-is-unit-testing/) where I elaborated on this a little bit (see the end of that post). – Jeroen Vannevel Apr 16 '15 at 14:22
  • I edited my comment to show how the arguments are used inside Bar constructor. In that code, there is no way to validate argumentOne and argumentTwo as they are not stored anywhere but used to calculate 'field' using a constant. This example is a simplified version of my problem to show how the arguments passed cannot be worked out unless the test also testes Bar constructor. – Juan Vega Apr 16 '15 at 15:11
  • 1
    Right, but you still don't show how it's used. Just test the code that eventually uses `field` and see if that goes perfectly. It implicitly tests that. – Jeroen Vannevel Apr 16 '15 at 15:14
  • @Jeroen is right. Ultimately that private field `field` has to have some kind of use in the class, even if there is no explicit getter for it. Assert something about that usage of `field` after it has been set. – Kevin Welker Apr 16 '15 at 15:47
  • 1
    Ok, so you are saying that the only way to test the factory method then is verifying that `field` contains the expected data after the logic in the constructor is applied. The reason why I asked this was because in my opinion it shouldn't matter how `field` is used or what it contains. The test should only verify the logic to workout the arguments for the constructor , not the constructor itself. That should be part of a unit test for Bar, not this one for Foo. But if there is no way to do that, then it makes sense that I should get `field` and assert it so the constructor is also tested here. – Juan Vega Apr 16 '15 at 15:58
  • No, we are explicitly saying that you should not test `field` specifically. We're saying that you should just use the `Bar` instance and test that instead. The `field` value will be used somewhere and that will eventually be implicitly tested through the public methods that you *can* test. This would be a lot easier to explain if you could show a clear example of how it's used ;) – Jeroen Vannevel Apr 16 '15 at 16:02
  • Sorry but I can't put the real example because is quite big. On that one, the parameters calculated in the factory method are used in the constructor to yet create another complex object inside. That's why for me it doesn't make sense to test the use of the method as it relies on several other ones. These other ones have their own unit test so a test in the factory method covering the use of them would be redundant. And the behaviour I expect would complicate a test that should be rather straightforward. I ended accessing the object inside and verifying the values I expect – Juan Vega Apr 16 '15 at 17:22
0

I've had similar situations. If your Bar has an equals method, you can always construct the Bar you expect the factory to build in your test and...

assertThat(actualbar).isEqualTo(expectedBar)

But if it doesn't make any sense to have "equals", or you cannot change "Bar" for whatever reason, you probably don't have much choice other than to get at the private fields of Bar using reflection to see if the correct value is set.

For example (this uses a "spring-test" class called ReflectionTestUtils)...

assertThat(ReflectionTestUtils.getField(actualBar, "argumentForBar")).isEqualTo(expectedValue);
BretC
  • 4,141
  • 13
  • 22
  • 1
    As commented on the previous reply, it makes more sense to me to test the constructor in a specific unit test for Bar rather than including it as part of the test for factory method in Foo. For me, what should be tested here is the logic that creates the final argument for Bar constructor, not how the constructor works (that should be another test). But if there is no other way, I guess I'm going to have to test the result from calling the constructor here. – Juan Vega Apr 16 '15 at 12:51