Unit testing factory methods which have a concrete class as a return type

前端 未结 5 419
醉梦人生
醉梦人生 2020-12-15 03:35

So I have a factory class and I\'m trying to work out what the unit tests should do. From this question I could verify that the interface returned is of a particular concret

相关标签:
5条回答
  • 2020-12-15 03:49

    If the factory is returning concrete types, and you're guaranteeing that your factory always returns a concrete type, and not null, then no, there isn't too much value in the test. It does allows you to make sure, over time that this expectation isn't violated, and things like exceptions aren't thrown.

    This style of test simply makes sure that, as you make changes in the future, your factory behaviour won't change without you knowing.

    If your language supports it, for your dependencies, you can use reflection. This isn't always the easiest to maintain, and couples your tests very tightly to your implementation. You have to decide if that's acceptable. This approach tends to be very brittle.

    But you really seem to be trying to separate which classes are constructed, from how the constructors are called. You might just be better off with using a DI framework to get that kind of flexibility.

    By new-ing up all your types as you need them, you don't give yourself many seams (a seam is a place where you can alter behaviour in your program without editing in that place) to work with.

    With the example as you give it though, you could derive a class from the factory. Then override / mock CreateADependency(), CreateAnotherDependency() and CreateAThirdDependency(). Now when you call CreateSomeClassWithDependencies(), you are able to sense whether or not the correct dependencies were created.

    Note: the definition of "seam" comes from Michael Feather's book, "Working Effectively with Legacy Code". It contains examples of many techniques to add testability to untested code. You may find it very useful.

    0 讨论(0)
  • 2020-12-15 03:50

    Often, there's nothing wrong with creating public properties that can be used for state-based testing. Yes: It's code you created to enable a test scenario, but does it hurt your API? Is it conceivable that other clients would find the same property useful later on?

    There's a fine line between test-specific code and Test-Driven Design. We shouldn't introduce code that has no other potential than to satisfy a testing requirement, but it's quite alright to introduce new code that follow generally accepted design principles. We let the testing drive our design - that's why we call it TDD :)

    Adding one or more properties to a class to give the user a better possibility of inspecting that class is, in my opinion, often a reasonable thing to do, so I don't think you should dismiss introducing such properties.

    Apart from that, I second nader's answer :)

    0 讨论(0)
  • 2020-12-15 03:50

    As I understand it you want to test that the dependencies are built correctly and passed to the new instance?

    If I was not able to use a framework like google guice, I would probably do it something like this (here using JMock and Hamcrest):

    @Test
    public void CreateSomeClassWithDependencies()
    {
        dependencyFactory = context.mock(DependencyFactory.class);
        classAFactory = context.mock(ClassAFactory.class);
    
        myDependency0 = context.mock(MyDependency0.class);
        myDependency1 = context.mock(MyDependency1.class);
        myDependency2 = context.mock(MyDependency2.class);
        myClassA = context.mock(ClassA.class);
    
        context.checking(new Expectations(){{
           oneOf(dependencyFactory).createDependency0(); will(returnValue(myDependency0));
           oneOf(dependencyFactory).createDependency1(); will(returnValue(myDependency1));
           oneOf(dependencyFactory).createDependency2(); will(returnValue(myDependency2));
    
           oneOf(classAFactory).createClassA(myDependency0, myDependency1, myDependency2);
           will(returnValue(myClassA));
        }});
    
        builder = new ClassABuilder(dependencyFactory, classAFactory);
    
        assertThat(builder.make(), equalTo(myClassA));
    }
    

    (if you cannot mock ClassA you can assign a non-mock version to myClassA using new)

    0 讨论(0)
  • 2020-12-15 03:51

    You can always check stuff with reflection. There is no need to expose something just for unit tests. I find it quite rare that I need to reach in with reflection and it may be a sign of bad design.

    Looking at your sample code, yes the Assert not null seems redundant, depending on the way you designed your factory, some will return null objects from the factory as opposed to exceptioning out.

    0 讨论(0)
  • 2020-12-15 03:52

    What we do is create the dependancies with factories, and we use a dependancy injection framework to substitute mock factories for the real ones when the test is run. Then we set up the appropriate expectations on those mock factories.

    0 讨论(0)
提交回复
热议问题