Liferay 7和JUnit:模拟本地自定义本地服务实用程序

时间:2019-02-20 16:05:29

标签: junit mockito liferay junit4 liferay-7

我正在尝试使用powermockito来模拟我的自定义本地服务实用程序,但是我总是遇到错误。

@RunWith(PowerMockRunner.class)
@PrepareForTest({ServiceSubscriptionLocalServiceUtil.class})
public class CStreamTest {
    @Before
    public void setUp() throws NoSuchFieldException, IllegalAccessException {
        .........
        mockStatic(ServiceSubscriptionLocalServiceUtil.class);
        .........
    }
}

我收到以下错误:

  

java.lang.ExceptionInInitializerError       在sun.reflect.GeneratedSerializationConstructorAccessor4.newInstance(未知来源)处       在java.lang.reflect.Constructor.newInstance(Constructor.java:423)       在org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:48)       在org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)       在org.mockito.internal.creation.instance.ObjenesisInstantiator.newInstance(ObjenesisInstantiator.java:19)       在org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker.createMock(SubclassByteBuddyMockMaker.java:47)       在org.mockito.internal.creation.bytebuddy.ByteBuddyMockMaker.createMock(ByteBuddyMockMaker.java:25)       在org.powermock.api.mockito.mockmaker.PowerMockMaker.createMock(PowerMockMaker.java:41)       在org.mockito.internal.util.MockUtil.createMock(MockUtil.java:35)       在org.mockito.internal.MockitoCore.mock(MockitoCore.java:62)       在org.mockito.Mockito.mock(Mockito.java:1896)       在org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator.createMethodInvocationControl(DefaultMockCreator.java:108)处       在org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator.doCreateMock(DefaultMockCreator.java:61)       在org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator.createMock(DefaultMockCreator.java:53)       在org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator.mock(DefaultMockCreator.java:40)       在org.powermock.api.mockito.PowerMockito.mockStatic(PowerMockito.java:62)       在com.e.c.stream.impl.test.CStreamTest.setUp(CStreamTest.java:50)

我添加了pom.xml的某些部分:

<dependency>
        <groupId>org.assertj</groupId>
        <artifactId>assertj-core</artifactId>
        <version>3.12.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <version>2.24.0</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-all</artifactId>
        <version>1.10.19</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-core</artifactId>
        <version>2.0.0</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-module-junit4</artifactId>
        <version>2.0.0</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-api-mockito2</artifactId>
        <version>2.0.0</version>
        <scope>test</scope>
    </dependency>

有什么想法吗?

谢谢

2 个答案:

答案 0 :(得分:1)

Liferay的*LocalServiceUtil类包含一堆静态方法,这些方法只是简化了实际服务实现的查找。假设您使用的是Liferay 7,则应仅利用服务本身,并依靠@Reference依赖项管理和使用它们的代码中的注入。这样,您只需要模拟未加载某些默认实现和查找的常规接口即可。

另一个选择是测试实现-并为服务上方的代码及其实现编写测试。通常很难编写UI层代码,例如portlet,以测试驱动的方式进行,其中模拟在很大程度上不依赖于服务和调用类的实现。

答案 1 :(得分:0)

通常,由服务构建器创建的服务实用工具类没有no arg构造函数,甚至没有构造函数。 但是,如果您查看日志,将会看到问题,这是您的问题:

该类的新实例在PowerMock中创建。

sun.reflect.GeneratedSerializationConstructorAccessor4.newInstance上的

java.lang.ExceptionInInitializerError(未知源) 在尝试为以下对象创建实例后:...

即使服务 utils通常没有构造函数,它们通常也会初始化静态成员,例如ServiceTracker。

您可以创建一个虚拟的服务impl,或者您的代码可以使用服务引用而不是util,可以嘲笑那个家伙。这里有几个选项,甚至是为您提供服务的模拟方法,也为您提供了虚拟服务。

但总而言之,您不能只做:

Sub HideRows()
'Ensure you declare all your variables
Dim ws1 As Worksheet, ws2 As Worksheet, lRow As Long
Dim ColumnOne As Integer, ColumnTwo As Integer
Dim dRng As Range, eRng As Range
Dim dRngCnt As Long, eRngCnt As Long

'Assign worksheets and variables
Set ws1 = ThisWorkbook.Sheets("Sheet1")
Set ws2 = ThisWorkbook.Sheets("Sheet2")

'Identifying the specific range as variable
Set dRng = ws2.Range("D2:D9")
Set eRng = ws2.Range("E2:E9")

'Assigning a variable to the countA will simplify your IF and ELSEIF statements
dRngCnt = Application.WorksheetFunction.CountA(dRng)
eRngCnt = Application.WorksheetFunction.CountA(eRng)

    With ws1
        ColumnOne = .Cells(1, .Columns.Count).End(xlToLeft).Column
        'I replaced "lastColumn" with "ColumnOne", because they are the same value, so you only need to use one
        lRow = .Cells(.Rows.Count, ColumnOne).End(xlUp).Row
        ColumnTwo = ColumnOne - 1

        If dRngCnt <> 0 Then 'I use the countA variable for column D Range
            For i = 1 To lRow
                If .Cells(i, ColumnTwo).Value = 0 Then 'Any 0s in the second to last columns will hide the row
                    .Rows(i).EntireRow.Hidden = True
                End If
            Next i

        ElseIf eRngCnt <> 0 Then 'I use the countA variable for column E Range
            For i = 1 To lRow
                If .Cells(i, ColumnOne).Value = 0 Then
                    .Rows(i).EntireRow.Hidden = True
                End If

            Next i
        Else
            Exit Sub

        End If
    End With

End Sub

因为这将创建一个实例,并且该实例具有需要初始化的静态成员。