【问题标题】:How do I unit test overridden methods which call super?如何对调用 super 的重写方法进行单元测试?
【发布时间】:2022-03-27 06:26:24
【问题描述】:

http://stackoverflow.com/questions/6645263/unit-testing-overridden-methods-which-call-super(这个问题的措辞相似但不一样)

我有一些类似的东西:

public class SuperClass {
   private int superClassInteger = 2;

   public void superClassMethod() {
      superClassInteger = 5;
   }

   public int getSuperClassInteger() {
      return superClassInteger();
   }
}

然后在我的测试中我有:

public class SuperClassTest {
   public void testSuperClassMethod() {
       SuperClass superClass = new SuperClass();
       superClass.superClassMethod();
       assertEquals(5, super.getSuperClassInteger())
   }
}

然后我有一个子类:

public class SubClass {
   private int subClassInteger = 2;

   public void subClassMethod() {
      super.superClassMethod();
      subClassInteger = 32;
   }

   public int getSuperClassInteger() {
      subClassInteger;
   }
}

然后是我对子类的测试:

public class SubClassTest {
   public void testSubClassMethod() {
       SubClass subClass = new SubClass();
       subClass.subClassMethod();
       assertEquals(5, subclass.getSuperClassInteger());
       assertEquals(32, subclass.getSubClassInteger())
   }
}

我的问题是为了测试子类的行为,我正在重复我为超类的测试代码。我可以取出:assertEquals(5, subclass.getSuperClassInteger());,因为我只想测试子类的业务逻辑。但是,这样做的问题是,如果有人不小心删除了对superClassMethod 的调用,测试仍然会通过。所以我需要验证是否调用了 super。测试此用例的常用方法是什么?

注意:我知道组合/策略模式与继承有助于解决这个问题,但要解决这个问题,你基本上是在说我不应该重写方法并在我的代码中调用 super(我很难相信会有永远不要用于)

【问题讨论】:

    标签: java unit-testing junit


    【解决方案1】:

    使用模拟间谍。您可以使用该测试框架检查几乎所有方法调用。

    https://github.com/mockito/mockito

    【讨论】:

      【解决方案2】:

      这可能不是您想要的答案(即不是解决方法),而是您应得的答案,但您永远不应该重写方法并调用 super。

      我正在开发一个做很多事情的遗留项目,维护、调试和测试都是一场噩梦。

      相反,最好使用带有模板方法模式的抽象类:

      之前

      public class SuperClass<T> {
        public void include(T t) {
          validate(T);
          dao.save(T);
        }
      
        // I've found code like that.
        public void validate(T t) {
        }
      }
      
      public class SubClass1 extends SuperClass<MyClass> {
        @Override
        public void include(MyClass mc) {
          doStuff(mc);
          doMoreStuff(mc);
          super.include(mc);
        }
      
        @Override
        public void validate(MyClass mc) {
          doValidationStuff();
        }
      }
      
      public class SubClass2 extends SuperClass<AnotherClass> {
        @Override
        public void include(AnotherClass ac) {
          doDifferentStuff();
          super.include(mc);
        }
      }
      

      之后

      public abstract class AbstractClass<T> {
        abstract void validate(T t);
      
        // this method can now be tested
        public void include(T t) {
          validate(T);
          dao.save(T);
        }
      }
      
      public class Class1 extends AbstractClass<MyClass> {
        public void validate(MyClass mc) {
          doValidationStuff();
          doStuff(mc);
          doMoreStuff(mc);
        }
      }
      
      public class Class2 extends AbstractClass<AnotherClass> {
        public void validate(AnotherClass ac) {
          doDifferentStuff();
        }
      }
      

      如您所见,这种重构简化了维护和测试,您不必担心在Class1和Class2测试中必须mock超类方法调用,并且代码封闭修改开放扩展,即,更易于维护。

      【讨论】:

      • 这对于大多数情况来说是合理的建议,但有时,尤其是在处理第三方 API 时,调用super() 是不可避免的。 (至少没有很多麻烦。)
      • 这样的话,我想最好在super调用之前调用override方法中的其他方法,然后测试这些方法。
      • "但是你永远不应该重写一个方法并调用 super" 什么?!
      【解决方案3】:

      使用 JMockit 并通过验证检查对 super 的调用。

      JMockit

      这个例子

      public void test {
        SubClass subClass = new SubClass();
        subClass.subClassMethod();
        new Verifications() {
          // mock only this method of superClass - and only in this test
          @Mocked (methods = "superClassMethod") 
          SuperClass superClass; 
          {
           superClass.superClassMethod();
           times = 1; // specify invocation count
          }
        };
      
       }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多