Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/386.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为工厂类创建的对象注入模拟_Java_Spring_Junit_Mockito - Fatal编程技术网

Java 为工厂类创建的对象注入模拟

Java 为工厂类创建的对象注入模拟,java,spring,junit,mockito,Java,Spring,Junit,Mockito,我有以下课程: public class MyClass { private Apple apple; public void myMethod() { apple = AppleFactory.createInstance(someStringVariable); .... .... .... } } 和测试类: @RunWith(MockitoJUnitRunner.class) public

我有以下课程:

public class MyClass {        
    private Apple apple;

    public void myMethod() {
       apple = AppleFactory.createInstance(someStringVariable);
       ....
       ....
       ....
    }
}
和测试类:

@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {

        @InjectMocks 
        MyClass myClass;

        @Test
        public void myMethod(){
         ...
         ...
         ...
        }
    }

如何在MyClass中将Apple实例作为模拟注入?

您有3种可能解决此问题:

抽象工厂:不要使用静态方法,而是使用具体的工厂类:

public abstract class AppleFactory {
    public Apple createInstance(final String str);
}

public class AppleFactoryImpl implements AppleFactory {
    public Apple createInstance(final String str) { // Implementation }
}
在测试类中,模拟工厂:

@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {

    @Mock
    private AppleFactory appleFactoryMock;

    @Mock
    private Apple appleMock;

    @InjectMocks 
    MyClass myClass;

    @Before
    public void setup() {
        when(appleFactoryMock.createInstance(Matchers.anyString()).thenReturn(appleMock);
    }

    @Test
    public void myMethod(){
     ...
     ...
     ...
    }
}
PowerMock:使用PowerMock创建静态方法的模拟。看看是怎么做的

可测试类:将
苹果
创建包装在一个
受保护的
方法中,并创建一个覆盖它的测试类:

public class MyClass {
   private Apple apple;

   public void myMethod() {
       apple = createApple();
       ....
       ....
       ....
   }

   protected Apple createApple() {
       return AppleFactory.createInstance(someStringVariable);
   }
}


@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {

    @Mock
    private Apple appleMock;

    @InjectMocks 
    MyClass myClass;

    @Test
    public void myMethod(){
     ...
     ...
     ...
    }

    private class TestableMyClass extends MyClass {
       @Override
       public void createApple() {
          return appleMock;
       }
    }
}
当然,在测试类中,您应该测试
TestableMyClass
,而不是
MyClass

我会告诉你我对每种方法的看法:

  • 抽象工厂方法是最好的方法——这是一种隐藏实现细节的清晰设计

  • 可测试类-是第二个需要最少更改的选项

  • PowerMock
    选项是我最不喜欢的选项——你没有追求更好的设计,而是忽略并隐藏你的问题。但这仍然是一个有效的选择

  • 除Avi提出的解决方案外,您还可以选择第四种可能性:

    注入工厂: 对我来说,这是当您已经有代码要重构时的最佳选择。使用此解决方案,您不必更改生产代码,只需更改工厂类和测试

    public class AppleFactory
    {
        private static Apple _injectedApple;
    
        public static createInstance(String str)
        {
            if (_injectedApple != null)
            {
                var currentApple = _injectedApple;
                _injectedApple = null;
                return currentApple;
            }
    
            //standard implementation
        }
    
        public static setInjectedApple(Apple apple)
        {
            _injectedApple = apple;
        }
    }
    
    现在,您可以简单地使用静态工厂:

    @RunWith(MockitoJUnitRunner.class)
    public class MyClassTest {
    
        @Mock
        private Apple appleMock;
    
        @InjectMocks 
        MyClass myClass;
    
        @Before
        public void setup() {
            AppleFactory.setInjectedApple(appleMock);
        }
    
        @Test
        public void myMethod(){
         ...
         ...
         ...
        }
    }
    

    关于Avi和Ev0oD的第一个答案。抽象类只能扩展,不能实现

      public abstract class AppleFactory {
        public abstract Apple createInstance(final String str);
    }
    
    public class AppleFactoryImpl extends AppleFactory {
        public Apple createInstance(final String str) { // Implementation }
    }
    

    太棒了,谢谢。我必须在我的情况下使用Mockito,所以我将使用抽象工厂或可测试类选项。@saravana_pc-我将我的排名添加到问题中。不过,您可以将
    mockito
    与powermock一起使用。在实现抽象工厂模式时,不必使用
    @Mock
    @InjectMock
    而是可以使用它们的等效方法(这样就可以去掉
    @RunWith(MockitoJUnitRunner.class)
    声明),接口不是更合适吗?我不理解抽象类的必要性,它不是只与实现一起工作吗?此外,虽然我喜欢这个想法,但它在某种程度上没有实现工厂的目标(您需要创建工厂的实例)。现在mockito可以模拟静态方法,但我不能使用更新的版本:,那么如何测试AppleFactory呢?