-2

I'm unsure of what else can be tested for my method TranslateResponse() .

It basically checks the type of translator and calls the translator's associated set() method.

public async Task TranslateResponse(Policy response)
{
    foreach (var t in await _translatorFactory.BuildTranslators())
    {
        var policyTranslator = t as IPolicyAwareTranslator;
        policyTranslator?.SetPolicy(response);
        var additionalInterestTranslator = t as IAdditionalInterestAwareTranslator;    
        additionalInterestTranslator?.SetAdditionalInterests(response.AdditionalInterests);
        var locationsTranslator = t as ILocationsAwareTranslator;
        locationsTranslator?.SetLocations(response.Locations);
    }
}

I'm writing test cases for the TranslateResponse() method. As far as I figured out, I'm verifying that the calls to respective methods happens based on the provided type of translator. The test case lines

Mock<ITranslator> mockedTranslator = new Mock<ITranslator>(); 
mockedTranslator.Setup(t => t.Translate(_translatorDataAccessor.Object));

var mockedPolicyTranslator = mockedTranslator.As<IPolicyAwareTranslator>();
mockedPolicyTranslator.Setup(t => t.SetPolicy(It.IsAny<Policy>()));

mockedPolicyTranslator.Verify(t => t.SetPolicy(It.IsAny<Policy>()), Times.AtLeastOnce);

My concerns are

  1. I'm curious to know whether I can test something more than verifying calls?

  2. Should I test for the logic of the set() method here or in it's own class? Even, then I'm not able to figure out what to Assert in the test case for the Set() which will set the private field with the passed in argument.

public class PolicyTranslator : ITranslator, IPolicyAwareTranslator
{      
    private Policy _policy;        
    public void SetPolicy(Policy policy)
    {
        _policy = policy;
    }  
    //translate()
}      
Eugene Podskal
  • 10,270
  • 5
  • 31
  • 53
Raida Adn
  • 405
  • 1
  • 6
  • 17

1 Answers1

0

whether I can test something more than verifying calls?

Basically there isn't much more that you can test, just

  1. add the same test for each used interface

Also, probably, you may want to

  1. Test that something implementing all interfaces is actually handled as each and every of those interfaces
  2. And perhaps a test that validates that there is a foreach loop (multiple translators) and not just .FirstOrDefault().
  3. Also, a case when there are no elements returned BuildTranslators is a valid one.

Should I test for the logic of the set() method here or in it's own class?

In most cases one shouldn't test SUT dependencies in unit-tests, because

  1. It may stop being a unit-test (if the dependency is complex enough) - not really that important (unless you maintain a very strict definition of unit-testing), but as we can see below.
  2. Testing dependencies through their consumers often unnecessarily complicates tests
    • You have to setup(often non-trivial) dependency itself.
    • You have to setup its consumer/user/SUT itself.
    • Then you have to construct the test in a way that actually calls that dependency.
    • Then validate that both the dependency and its consumer worked as intended.
    • And the complexity/number of tests does not grow linearly - if you can have 100%/reasonable coverage with 4 tests for SUT and 4 for its dependency, while achieving the same degree of coverage with integration level tests may require anywhere between 4 and 4*4 or even more tests.

For simple cases, like, for example, the code in question it will actually simplify things, as you no longer have to mock IPolicyAwareTranslator and can simply test the value is set as intended, but even in such a case there is a minor trap:

  1. We can no longer be sure that the method handles IPolicyAwareTranslator - someone could replace var policyTranslator = t as IPolicyAwareTranslator; with var policyTranslator = t as PolicyTranslator; and the test will still pass, though it can no longer handle our business-critical AwesomePolicyAwareTranslator.

You may say that it is basically movie-plot-threat and simply test multiple classes as one subsystem if you know what you are doing and it is not too arduous.

Though in most cases I would argue against such "low-level integration testing" when you can have proper isolated, simpler! unit tests.

low-level integration testing - that's basically a made-up term, but I'd say that it suits such tests well enough.


Still, there are some cases when having coarser-grained "low-level integration tests" may be slightly better than having unit-tests covering the same code:

  1. Usually it happens when individual components end up being so small, that unit-testing them does not allow you to express domain concepts/have any real degree of trust in the multitude of real scenarios, while tests higher up the test pyramid are too few/difficult to run/maintain.

In such a case "low-level integration test" gives you a lot for a reasonable price (we should not forget that 100% coverage is unobtainable, proper test pyramid can't be build for cheap, so cost-effective approach to testing is a necessity).

Eugene Podskal
  • 10,270
  • 5
  • 31
  • 53