In JUnit 4, I use the following setup to test my EJB beans:
#RunWith(EJBContainerRunner.class)
public class MyEETestWithOneOpenEJB {
#Inject
private ACdiBean bean;
#Test
public void theTest() {
// do test
}
}
But in JUnit 5, there is no #RunWith(...) anymore.
Question: How to test with JUnit 5?
You will need to write your own EJBContainerExtension to replace the Runner or find an already existing one. The latter is unfortunately not very likely at this moment, JUnit5 is still not in GA and there are not many official extensions yet.
If you want to, read about JUnit 5 extension model here
TomEE 8 (since 8.0.7) supports testing with JUnit 5 only (without a transient dependency towards JUnit 4).
The Legacy Way
The legacy EJBContainerRunner was replaced by a related JUnit 5 extension.
If you are using Maven, you would need to add the following dependency to your pom file:
<dependency>
<groupId>org.apache.tomee</groupId>
<artifactId>openejb-junit5-backward</artifactId>
<version>8.0.9</version>
<scope>test</scope>
</dependency>
Subsequently, you can replace
#RunWith(EJBContainerRunner.class)
with
#RunWithEjbContainer
which is a pure JUnit 5 extension. There is no need to add any JUnit 4 dependency into your classpath. A usage example can be found in the module's test source at the TomEE GitHub repository.
The Modern Way
In the same release, the ApplicationComposer was enhanced to support JUnit 5 as an extension. To use it, add
<dependency>
<groupId>org.apache.tomee</groupId>
<artifactId>openejb-junit5</artifactId>
<version>8.0.9</version>
<scope>test</scope>
</dependency>
to your classpath. ApplicationComposer does not require classpath scanning and is faster than the alternative mentioned above.
Just add #RunWithApplicationComposer to your JUnit 5 test class. By default, the container lifecycle is bound to the lifecycle of the test instance. However, other modes are available as well:
PER_EACH: A container is started for each test method
PER_ALL: A container is started for each test class
PER_JVM: A container is started once per JVM
AUTO (default): A container is started based on the test instance lifecycle.
An example can be found in the examples section of the TomEE GitHub repository.
Related
I want to mock a static method in JUnit 5. But unfortunately, JUnit 5 doesn’t support Mockito. Is there another method to achieve the same other than reverting back to JUnit 4?
From Mockito 3.4.0 (2020-07-10), it is possible to mock static methods out of the box even in JUnit 5, without any extension.
In the documentation, you can find an example: 48. Mocking static methods (since 3.4.0)
Important note: You need to use inline mock maker. So the dependency to use is not the core one:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>3.4.6</version>
<scope>test</scope>
</dependency>
Example:
Class under test:
package teststatics;
public class FooWithStatics {
public static Long noParameters() {
return System.currentTimeMillis();
}
public static String oneParameter(String param1) {
return param1.toUpperCase();
}
}
Test class:
package teststatics;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
public class FooWithStaticsTest {
#Test
void testStatic() {
// Before mock scope, usual behavior.
assertNotEquals(0L, FooWithStatics.noParameters());
assertNotEquals("yyy", FooWithStatics.oneParameter("xxx"));
// Mock scope
try (MockedStatic mocked = mockStatic(FooWithStatics.class)) {
// Mocking
mocked.when(FooWithStatics::noParameters).thenReturn(0L);
mocked.when(() -> FooWithStatics.oneParameter("xxx")).thenReturn("yyy");
// Mocked behavior
assertEquals(0L, FooWithStatics.noParameters());
assertEquals("yyy", FooWithStatics.oneParameter("xxx"));
// Verifying mocks.
mocked.verify(times(1), FooWithStatics::noParameters);
mocked.verify(times(1), () -> FooWithStatics.oneParameter("xxx"));
}
// After mock scope returns to usual behavior.
assertNotEquals(0L, FooWithStatics.noParameters());
assertNotEquals("yyy", FooWithStatics.oneParameter("xxx"));
}
}
The short answer is no, as the Mockito team is done with their work and is waiting for the JUnit team for an extension and are discussing here a lot.
With some overhead you can: As JUnit 5 provides support for running legacy JUnit 4, and there you can use Mockito. So you can create tests in Junit4 for these cases:
A sample project for migration setup with gradle and with mvn. From there I am using PowerMock 2.0 beta with Mockito 2.
The reason why Mockito doesn't provide static methods mocking at the moment is because of the common belief that static method shouldn't need to be mocked.
However, there is an open item for Mockito here that discusses the issue.
While this doesn't answer your question, in general it tells you why you shouldn't need the feature at all or will allow you to join the conversation with your ideas.
Make sure to have mockito-inline dependency in your POM file
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>3.6.28</version>
<scope>test</scope>
</dependency>
In my case I had to test scenario where exception thrown static method encode() of URLEncoder Class, so for that
try (MockedStatic theMock = mockStatic(URLEncoder.class)) {
theMock.when(() -> URLEncoder.encode("Test/11", StandardCharsets.UTF_8.toString()))
.thenThrow(UnsupportedEncodingException.class);
when(restClient.retrieveByName("Test%2F11")).thenReturn(null);
Assertions.assertThrows(ResponseStatusException.class, ()->service.retrieveByName("Test/11"));
}
We can mock a static method by JMockit.
JMockit is used for mocking the external dependencies outside the test boundary, similar to Mockito and other such mocking libraries.
The most important feature of JMockit is that it lets us mock anything, even the things that are hard to mock with other libraries such as constructors, static and final methods. It even allows mocking the member fields and initialization blocks as well.
Follow the below steps to enable JMockit:
The JMockit artifact is located in the central Maven repository, add the JMockit dependency in pom.xml
<!-- https://mvnrepository.com/artifact/org.jmockit/jmockit -->
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>1.49</version>
<scope>test</scope>
</dependency>
Mock the Class method in TestClass:
public class TestClass{
#Test
public void testMethod() {
new MockUp<ClassName>(){
#Mock
//mock the method here
};
}
}
Follow the tutorial to know more about how to use the JMockit.
I have created several junit test suites which include several test cases.
Looks like as below:
#RunWith(Suite.class)
#Suite.SuiteClasses({
HttpAPICreationTest.class,
HttpAPIVerifyTest.class,
HttpAPIDeletionTest.class
})
public class HttpAPITestSuite {
}
#RunWith(Suite.class)
#Suite.SuiteClasses({
HtmlSeleniumScriptBatchCreationTest.class,
PagingVerificationTest.class,
HtmlSeleniumScriptBatchDeletionTest.class
})
public class PagingTestSuite {
}
Now I want to execute my HttpAPITestSuite and PagingTestSuite in parallel, and for now, HttpAPICreationTest.class, HttpAPIVerifyTest.class, HttpAPIDeletionTest.class are executed serial, not in parallel> Also, I don't want to break their order.
So how can I make my suites run parallel and keep the original order for their inner test cases: run HttpAPICreationTest.class and HtmlSeleniumScriptBatchCreationTest.class in parallel, and keep the case of HttpAPICreationTest.class always before HttpAPIVerifyTest.class and HttpAPIDeletionTest.class.
If you are using maven, use Surefire forks. If you want behavior part parallel, part serial, then you would need to execute the plugin multiple times, with different settings. But generally speaking, the jUnit runners/plugins are not well suited for "run tests as a graph", test ordering is done much better way in TestNG.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<forkCount>3</forkCount>
<reuseForks>true</reuseForks>
</configuration>
</plugin>
More documentation: http://maven.apache.org/surefire/maven-surefire-plugin/examples/fork-options-and-parallel-execution.html
Edit: if you are running tests from Idea, then Idea (2016.3) has its own settings in Run tests configuration (and does not pick up maven settings). And it supports only one global settings per tests execution (serial/method_fork/class_form + fork count)
I am creating a cross-platform project with MvvmCross v3 and Xamarin solution and i would like to create some unit-tests.
This seems a bit outdated, so i was trying to follow this and it worked as expected.
However, I am now making an attempt to unit-test some of my domain services, which are dependent on platform specific MvvvCross plugins (e.g ResourceLoader).
Running the test results in the following exception:
Cirrious.CrossCore.Exceptions.MvxException: Failed to resolve type
Cirrious.CrossCore.Plugins.IMvxPluginManager.
I assume that IMvxPluginManager is probably registered in the Setup flow, and that I need to include platform implementation of the plugins in my project, yet I was wondering what would be the preferred way of setting up my unit-test project? Is there something that I am missing?
Is there any updated tutorial for the above task?
Are there already any plugin platform extensions that supports test environment, or should I make an attempt to write them by myself?
In general, you shouldn't be loading the plugins or a real MvxPluginManager during your service tests.
Instead your unit tests should be registering mock types for the interfaces that your services need to use.
var mock = new Mock<INeedToUse>();
// use mock.Setup methods
Ioc.RegisterSingleton<INeedToUse>(mock.Object);
// or you can use constructor dependency injection on INeedToUse instead
You can also register a mock IMvxPluginManager if you really need to, but in the majority of cases I don't believe you should need that. If you've got a case where you absolutely need it, please post a code sample - it's easier to talk in code than text.
This scenario should be well possible. I wanted to UnitTest my SqlLite service implementation. I did the following to get it to work:
Create a Visual Studio unit test project
Add a reference to .Core portable library project
Add a nuget reference To MvvmCross Test Helper
Add a nugget reference to MvvmCross SqlLite Plugin
( this will make use of the WPF implementation of SqlLite)
Download the SqlLite windows library and copy these into your test project
Sql Lite Download location
And make sure to add the sqllite3.dll to the root of your unit test project and set the "Copy to Output Library" to "Copy always". This will make sure the actual sqllite database is copied to the unit test dll location. (Check that the DLL is copied to your bin/debug folder)
Then write you unit test the following way:
[TestClass]
public class SqlServiceTests:MvxIoCSupportingTest
{
private readonly ISQLiteConnectionFactory _factory;
public SqlServiceTests()
{
base.ClearAll();
_factory = new MvxWpfSqLiteConnectionFactory();
Ioc.RegisterSingleton<ISQLiteConnectionFactory>(_factory);
}
[TestMethod]
public void YourSqlLiteTest()
{
// Arrange
var si = new SqlDataService(_factory);
var list = si.GetOrderList();
}
}
I haven't tested this with my viewmodel. By using the IoC.RegisterSingleton method the SqlConnectionFactory should be readyli available for your viewmodels.
I am testing a Scalatra servlet that does some important initialization in its init(context: ServletContext) method.
During tests (with ScalatraSuite) that init is not executed.
How should I do my important initialization when I am testing?
That Scalatra testing page (section "Testing FAQ") does not reveal that.
Extra Info:
The "Testing FAQ" section states
scalatra-test is built on Jetty's [ServletTester][3]
but I also could not extract any information from the internet on how to run the init if I were coding in java.
You can use the servletContextHandler for those things in a test.
You can set initParameters with servletContextHandler.setInitParameter("the.param", "the.value")
I'll update the docs so they won't say that the testing support is added through jetty tester.
In fact it uses an embedded jetty server so the init method should get called.
I am currently working on an inherited codebase. One of the critical missing pieces is unit testing. I seem to have run into a roadblock while trying to set up some unit tests in NUnit.
I created a separate unit testing project as normal, added the necessary references to SubSonic, NUnit and the various DLLs created by the application and set up a dummy unit test to ensure everything is set up correctly. The problems started when I attempted to reference some of the objects generated by SubSonic. I created this test to list users:
[Test]
public void CanListUsers()
{
UserCollection users = UserController.List(UserController
.Query()
.Where(User.Columns.IsDeleted, false));
Assert.IsNotNull(users);
}
and got this exception:
Can't find the SubSonicService in your
application's config
I fixed that by pulling out the parts of the Web.config that were related to SubSonic into an App.config in the unit testing project. Now, when I rerun the unit tests, I get:
UnitTests.TestClass.CanListUsers:
System.Reflection.TargetInvocationException
: Exception has been thrown by the
target of an invocation. ---->
System.Configuration.ConfigurationErrorsException
: Could not load type
'Utility.SqlSubsonicProvider' from
assembly 'System.Web, Version=4.0.0.0,
Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a'.
This exception has me confused because SqlSubsonicProvider is a class in the Utility namespace and can be seen in Object Browser so why is it being looked for in System.Web?
Edit: Okay, I have rearranged the namespaces in the solution so that they make more sense. I think that fixed the above error. Unfortunately I'm now getting this error:
ChannelMechanics.UnitTests.TestClass.CanListVendors:
System.Reflection.TargetInvocationException : Exception has been thrown by the target
of an invocation.
----> System.NullReferenceException : Object reference not set to an instance of
an object.
What's even stranger is that the unit test passes when I use Visual Studio's "Attach to Process" command in the Debug menu and attach to the NUnit GUI. My theory was that the null object would be easily spotted from within the debugger.
If it helps, my App.config looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="SubSonicService"
type="SubSonic.SubSonicSection, SubSonic"
requirePermission="false"/>
</configSections>
<connectionStrings>
<add name="DatabaseConnection"
connectionString="*removed*"/>
</connectionStrings>
<SubSonicService defaultProvider="TestProvider">
<providers>
<clear />
<add name="TestProvider"
type="SubSonic.SqlDataProvider, SubSonic"
connectionStringName="DatabaseConnection"
generatedNamespace="Test"/>
</providers>
</SubSonicService>
</configuration>
The exception details are:
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type,
Boolean publicOnly, Boolean noCheck, Boolean& canBeCached,
RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis,
Boolean fillCache)
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly,
Boolean skipVisibilityChecks, Boolean skipCheckThis, Boolean fillCache)
at System.Activator.CreateInstance[T]()
at SubSonic.ActiveController`2.Query()
at UnitTests.TestClass.CanListVendors() in UnitTests\TestClass.cs:line 59
--NullReferenceException
at DataAccess.Vendor.GetTableSchema() in DataAccess\Generated\Models\Vendor.cs:line 376
at DataAccess.Vendor.SetSQLProps() in DataAccess\Generated\Models\Vendor.cs:line 42
at DataAccess.Vendor..ctor() in DataAccess\Generated\Models\Vendor.cs:line 35
The test that I am running is basically the same as the one listed above except it's Vendors rather than Users that should be getting listed.
[Test]
public void CanListVendors()
{
VendorCollection vendors = VendorController.List(
VendorController
.Query()
.Where(Vendor.Columns.IsDeleted, false));
Assert.IsNotNull(vendors);
}
I would suggest there is a System.Web.Utility namespace, and you get this wrong error message because the compiler "thinks" he has to look inside this namespace for resolving the class.
Please check that your test project is set to target framework "Framework 4" and not "Framework 4 Client Profile".
Missing ".NET Framework 4 Client Profile" as target framework in "New Project" window
This seems to be working now. The only change I made within the project was to create a separate test project using Visual Studio's unit test capabilities. The only other explanation I can think of is that something troublesome got thrown out of memory when I rebooted the computer between yesterday evening and today.
For the benefit of anyone stumbling on this question in the future, here is a summary of the steps I took to get NUnit testing a DAL generated by SubSonic:
Create new class library project.
Add necessary references - I added the DAL, NUnit and SubSonic.
Add an App.config file so that
SubSonic knows where to find the
SubSonic service. All I did for this
was to pull out the parts in
Web.config that were related to
SubSonic.
Add a test class and start adding tests to it.
If your tests are inexplicably failing, make sure the "Copy to Output Directory" is set to "Copy if newer" for the App.config that was added, make sure the provider name in App.config matches the provider name used in the DAL classes and, if all else fails, reboot!
Do you always have SubSonic not Subsonic?
This is the relevant section from my nunit projects config file which works...
<configSections>
<section name="SubSonicService"
type="SubSonic.SubSonicSection, SubSonic"
requirePermission="false"/>
</configSections>
<SubSonicService defaultProvider="TAProvider">
<providers>
<clear />
<add name="TAProvider"
type="SubSonic.SqlDataProvider, SubSonic"
connectionStringName="TATesting"
generatedNamespace="DALTA"/>
</providers>
</SubSonicService>