Unit test for togglz feature on and off
Asked Answered
V

3

7

We are using Togglz to turn functionalities on and off in our project. The following TogglzFeature Enum is implementing org.togglz.core.Feature interface

public enum TogglzFeature implements Feature {

    @EnabledByDefault
    @Label("Current XSLT code")
    FEATURE_XSLT,

    @Label("NEW JAXB code")
    FEATURE_JAXB;

    public boolean isActive() {
        FeatureManager manager = FeatureContext.getFeatureManager();
        return manager.isActive(this);
    }

}

Then one of the methods under test (say mut_1(params)) is checking the enum, something like

if(TogglzFeature.FEATURE_JAXB.isActive()) { dothings();}

Note that togglz feature is not in the params of mut_1. The mut_1 just picks it up from context in runtime.

So what is the best way to let the mut_1() know that I want TogglzFeature.FEATURE_JAXB.isActive() to return true?

I tried this with Mockito/PowerMock

@RunWith(PowerMockRunner.class)
@PrepareForTest({TogglzFeature.class})
public class myTestClass {

    //private members and set up

    @Test
    public void testTogglz(){
        PowerMockito.mockStatic(TogglzFeature.class);
        BDDMockito.given(TogglzFeature.FEATURE_JAXB.isActive()).willReturn(true);

        //execution and verification
    }
}

And the system spits all these on me

java.lang.VerifyError: Inconsistent stackmap frames at branch target 128
Exception Details:
  Location:
    com/lmig/ci/rate/togglz/TogglzFeature.values()[Lcom/lmig/ci/rate/togglz/TogglzFeature; @128: ldc
  Reason:
    Type 'java/lang/Object' (current frame, locals[1]) is not assignable to '[Lcom/lmig/ci/rate/togglz/TogglzFeature;' (stack map, locals[1])
  Current Frame:
    bci: @120
    flags: { }
    locals: { top, 'java/lang/Object', null, null }
    stack: { 'java/lang/Object', null }
  Stackmap Frame:
    bci: @128
    flags: { }
    locals: { top, '[Lcom/lmig/ci/rate/togglz/TogglzFeature;' }
    stack: { }
  Bytecode:
    0x0000000: 1248 b800 4e12 4f03 bd00 5112 53b8 0057
    0x0000010: 1259 b800 5f4b 2a01 4c01 4d2b 127e b800
    0x0000020: 8012 8112 82b8 0085 b800 894e 2db2 0063
    0x0000030: a600 0ab2 0063 4da7 0008 2dc0 008a 4d2c
    0x0000040: a500 082a c000 64b0 014c 014d 2b12 8bb8
    0x0000050: 0080 128c 128d b800 85b8 0089 4e2d b200
    0x0000060: 63a6 000a b200 014d a700 082d c000 644d
    0x0000070: 2c4c 014d 014e 2b01 a500 082b 4ea7 0009
    0x0000080: 128f b800 804e 2d12 9003 bd00 5112 91b8
    0x0000090: 0093 1295 b800 963a 0419 04b2 0063 a600
    0x00000a0: 0b2b b600 984d a700 0919 04c0 008a 4d2c
    0x00000b0: c000 03b0                              
  Stackmap Table:
    full_frame(@58,{Object[#81],Top,Top,Object[#81]},{Object[#81]})
    full_frame(@63,{Object[#81],Top,Object[#81]},{Object[#81]})
    chop_frame(@72,3)
    full_frame(@107,{Top,Top,Top,Object[#81]},{})
    full_frame(@112,{Top,Top,Object[#81]},{})
    full_frame(@128,{Top,Object[#50]},{})
    append_frame(@134,Top,Object[#81])
    full_frame(@169,{Top,Top,Top,Top,Object[#81]},{})
    full_frame(@175,{Top,Top,Object[#81]},{})

    at java.lang.Class.getDeclaredConstructors0(Native Method)
    at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
    at java.lang.Class.getDeclaredConstructors(Class.java:2020)
    at org.powermock.api.mockito.repackaged.ClassImposterizer.setConstructorsAccessible(ClassImposterizer.java:86)
    at org.powermock.api.mockito.repackaged.ClassImposterizer.imposterise(ClassImposterizer.java:72)
    at org.powermock.api.mockito.internal.mockcreation.MockCreator.createMethodInvocationControl(MockCreator.java:122)
    at org.powermock.api.mockito.internal.mockcreation.MockCreator.createMock(MockCreator.java:70)
    at org.powermock.api.mockito.internal.mockcreation.MockCreator.mock(MockCreator.java:47)
    at org.powermock.api.mockito.PowerMockito.mockStatic(PowerMockito.java:71)
    at com.lmig.ci.rate.orchestration.OrchestratorTest.workerCompShouldGoThroughSteppedAudit(OrchestratorTest.java:97)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:316)
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:89)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:300)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:131)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.access$100(PowerMockJUnit47RunnerDelegateImpl.java:59)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner$TestExecutorStatement.evaluate(PowerMockJUnit47RunnerDelegateImpl.java:147)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.evaluateStatement(PowerMockJUnit47RunnerDelegateImpl.java:107)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:288)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:208)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:147)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:121)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:123)
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:121)
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
    at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Vespiary answered 14/7, 2016 at 17:44 Comment(0)
T
10

You don't need to mock anything. Togglz ships with a special module for unit testing feature toggles. Have a look here:

http://www.togglz.org/documentation/testing.html

There is for example a JUnit rule which provides a simple way to toggle features:

public class SomeJunitTest {

  @Rule
  public TogglzRule togglzRule = TogglzRule.allEnabled(MyFeatures.class);

  @Test
  public void testToggleFeature() {

    // all features are active by default  
    assertTrue(MyFeatures.FEATURE_ONE.isActive());

    // you can easily modify the feature state using the TogglzRule
    togglzRule.disable(MyFeatures.FEATURE_ONE);
    assertFalse(MyFeatures.FEATURE_ONE.isActive());

  }

}
Toot answered 14/7, 2016 at 20:18 Comment(3)
can we mock parameter with TooglzRule as well ?Joliejoliet
You are talking about feature strategy parameters? No, in your tests you should just verify that your code works if the feature is on or off. There won't be any strategy in your test, so parameters make no sense.Toot
This would result in flaky test cases, as unit tests can run in parallel and this TogglzRule has static behaviour.Peripteral
S
3

Since the JUnit5 implementation of the Togglz test library, it is even easier to perform this by using an annotation.

maven dependency

<dependency>
    <groupId>org.togglz</groupId>
    <artifactId>togglz-junit</artifactId>
    <version>3.1.2</version>
    <scope>test</scope>
</dependency>

JUnit 5 test code using the Togglz annotations

@Test
@AllEnabled(MyFeature.class)
void isActive_whenEnabled() {
    Assertions.assertThat(MyFeature.ONE.isActive()).isTrue();
}

@Test
@AllDisabled(MyFeature.class)
void isActive_whenDisabled() {
    Assertions.assertThat(MyFeature.ONE.isActive()).isFalse();
}
Sneed answered 16/3, 2022 at 12:32 Comment(2)
While the comment overall is useful, the mentioned togglz-junit5 dependency is wrong. It has been stuck on outdated 2.8.0 version, and official documentation togglz.org/documentation/testing.html mentions using togglz-junit dependency instead (without *5 suffix)Mislay
Thanks for reporting this, I included your remark in the original post.Sneed
E
0
featureManager.setFeatureState(new FeatureState(MyFeatures.FOO, true))

FeatureManager

Epsilon answered 19/5, 2021 at 21:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.