Assuming my system under test looks like this:
public class SysUnderTest {
public int foo() {
Trouble trouble1 = new Trouble();
Trouble trouble2 = new Trouble();
return trouble1.water(1) + trouble2.water(2);
}
}
The test will looks something like
public class DummyTest {
#Tested SysUnderTest sut;
#Mocked Trouble trouble;
#Test
public void testTrouble() {
new Expectations() {{
trouble.water(anyInt); returns(10, 20);
}};
assertThat("mocked result", sut.foo(), is(30));
new FullVerificationsInOrder() {{
Trouble t1 = new Trouble();
Trouble t2 = new Trouble();
t1.water(1);
t2.water(2);
}};
}
}
However, Trouble is actually a 3rd-party lib class that I have no control, which it does static initialization which will fail in testing env.
public class Trouble {
static {
troubleInitialize();
};
public int water(int i) {
return 0;
}
private static void troubleInitialize() {
throw new RuntimeException("Trouble");
}
}
I know I can use MockUp<Trouble> to get rid of the static initializer but I have no idea how to make use of it in case as I want to (in my realistic case) be able to distinguish the two new instances (created in SysUnderTest) and verify their invocations. I have tried different ways but all failed with some reasons
Adding a new MockUp<Trouble>(){#Mock void $clinit(){} }; in #Before/#BeforeClass, and keep #Mocked Trouble trouble;. It seems not working because the mockup action happens after the DummyTest class is loaded, which will load (unmodified) Trouble class which will throw exception during static initialization
Adding the new Mockup in a TestSuite and call the DummyTest in suite, similar problem as 1.
Simply put the behavior of returning 20, 30 in the fake class, and remove usage of Expectations/Verifications but I have no way to verify which instance is called with what parameter.
Is there a better way to solve my problem? Actually I would want to keep using Expectaitons/Verifications, all I want is some way to disable the static initializer during unit test.
Use stubOutClassInitialization to change the mocked class's static init to an empty method when using Mocked.
#Mocked(stubOutClassInitialization=true) Trouble trouble;
Related
Say, a test needs a parameter that is only known when the tests are about to run.
#ExtendWith(MyParameterExtension.class)
public class Test {
protected final MyParameter p;
public Test(MyParameter p) {}
#Test
public void test() { assertSuccess(TestedCode.doComplexThing(p)); }
}
Only before the tests are executed, the specific contents of MyParameter instance can be determined. So I can have a resolver extension that simple pastes that parameter value where needed:
class MyParameterExtension implements ParameterResolver {
private final MyParameter myParameter;
public MyParameterExtension(MyParameter p) {
myParameter = p;
}
#Override
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {
return (parameterContext.getParameter().getType() == MyParameter.class);
}
#Override
public MyParameter resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {
return myParameter;
}
}
I run the tests by starting Junit5 from my own code. That's when I can determine what the corresponding parameter values are. Let's say these parameters drive the behavior of the tests, and a user can specify (i.e., over a CLI) the values that a run should use.
How do I register the extension with the test run, as I'm about to commence it?
void launchSuite(List<DiscoverySelector> selectors, Object something) {
// The input to this are all the necessary selectors.
LauncherDiscoveryRequest ldr = LauncherDiscoveryRequestBuilder.request()
.selectors(selectors).build();
Launcher launcher = LauncherFactory.create();
TestPlan plan = launcher.discover(ldr);
MyParameter myParameter = new MyParameter(something);
MyParameterExtension ext = new MyParameterExtension(myParameter);
// $TODO: how do I register my extension with the test run
// before starting it?
launcher.execute(plan);
}
Auto-registering extensions doesn't help me (how would that process know the value of MyParameter)
Using #RegisterExtension in the test code doesn't help me (A static block in the test code won't know the proper input for constructing instances of MyParameter)
Looking at the mechanics of launching the test, I don't see anything that lets me register those extensions in advance.
I considered using a ThreadLocal field in an extension registered statically but AFAIU, this won't (reliably) work because JUnit may create its own threads at least in certain cases.
I considered sticking the value of MyParameter in the "extension context", but I don't see a way to grab a hold of that before the test execution starts either. The root context is created in JupiterEngineDescriptor that is, if nothing else, all internal API.
The obvious solution is to stick the parameter in a static field somewhere, but that would preclude me from running tests with different parameters in parallel, unless I resort to loading tests into isolated class loaders, which sounds too cumbersome for something that I believe should be simpler. After all, all of the contexts of a test run are otherwise fully isolated.
What I'm ultimately trying to do, at then, as to make something like this possible:
// ...
new Thread(()->launchSuite(selectors, "assume Earth gravity")).start();
new Thread(()->launchSuite(selectors, "assume Mars gravity")).start();
So what's are the reasonable ways to wire something this together?
Let's start with the one thing that does not work: Using the launcher API.
The launcher API is a platform feature, whereas extensions are Jupiter-related. That's why there is no mechanism to register an extension in the API.
What should work, though, is #RegisterExtension - although you claim it would not. As the documentation shows it is not restricted to static fields. Therefore, whatever you do here:
MyParameter myParameter = new MyParameter(something);
MyParameterExtension ext = new MyParameterExtension(myParameter);
could be done in a static method to instantiate an extension during runtime:
public class Test {
private static MyParameterExtension createExtension() {
MyParameter myParameter = new MyParameter(something);
return new MyParameterExtension(myParameter);
}
#RegisterExtension
private MyParameterExtension my = createExtension();
#Test
public void test(MyParameter p) {
assertSuccess(TestedCode.doComplexThing(p));
}
}
If that doesn't work in your case, some information is missing from your problem statement IMO.
Update
If your extension creation code requires parameters that can only be determined at launch time, you have the option of adding configuration parameters to the discovery request:
LauncherDiscoveryRequest ldr = LauncherDiscoveryRequestBuilder.request()
.configurationParameter("selectors", "assume Earth gravity")
.selectors(selectors).build();
This parameter can then be retrieved within the extension:
class MyParameterExtension implements ParameterResolver {
...
#Override
public MyParameter resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {
var selectors = extensionContext.getConfigurationParameter("selectors").orElse("");
return new MyParameter(selectors);
}
}
I have a test class that has several tests. At the moment I have this to start up the server, wipe the database etc:
#ClassRule
public static final DropwizardAppRule<ServiceConfig> RULE =
new DropwizardAppRule<ServiceConfig>(ServiceApp.class, ResourceHelpers.resourceFilePath("config.yml"));
All my tests work with this individually. But when I run them all together some fail since other tests modify data. I tried doing the following but I'm getting null pointers when calling RULE.getPort():
#ClassRule
public static DropwizardAppRule<ServiceConfig> RULE;
#Before
public void beforeClass() {
RULE = new DropwizardAppRule<ServiceConfig>(ServiceApp.class, ResourceHelpers.resourceFilePath("config.yml"));
}
I would have expected this to work but it doesn't seem to set the values of RULE properly. Any ideas?
Hi,
I don't know how to handle db "from within" DropwizardAppRule, so I may not really answer your question... I'm actually having another issue myself trying with DropwizardAppRule not properly being setup and torn down between tests. (So if you made progress going this way I'd like you insights).
Anyway, I think you need to handle your DB outside DropwizardAppRule and give it in the Rule. We resolved DB clearing by relying on custom and external TestsRules:
public class CockpitApplicationRule implements TestRule {
public static class App extends CockpitApplication<CockpitConfiguration> {
// only needed because of generics
}
public final DropwizardAppRule<CockpitConfiguration> dw;
public final EmbeddedDatabaseRule db;
public CockpitApplicationRule(String config, ConfigOverride... configOverrides) {
this.db = EmbeddedDatabaseRule.builder()
.initializedByPlugin(LiquibaseInitializer.builder().withChangelogResource("migrations.xml").build())
.build();
this.dw = new DropwizardAppRule<>(App.class, ResourceHelpers.resourceFilePath(config),
ConfigOverride.config("database.url", () -> this.db.getConnectionJdbcUrl()));
}
#Override
#Nullable
public Statement apply(#Nullable Statement base, #Nullable Description description) {
assert base != null;
assert description != null;
return RulesHelper.chain(base, description, dw, RulesHelper.dropDbAfter(db), db);
}
public DSLContext db() {
return DSL.using(db.getConnectionJdbcUrl());
}
}
Basically we override TestRule apply(...) to chain custom Statements. There's our RulesHelper if you want to take a look. That way the DB is cleanly handled by the Rules, we can fill our test DB in test classes using #Before setup methods.
org.zapodot.junit.db.EmbeddedDatabaseRule Is an external dependency that allows us to rather easily instantiate a DB for our tests.
The RulesHelper.dropDbAfter does the actual cleaning:
public static TestRule dropDbAfter(EmbeddedDatabaseRule db) {
return after(() -> DSL.using(db.getConnectionJdbcUrl()).execute("DROP ALL OBJECTS"));
}
You should be able to setup and clean the DB from #Before and #After methods without fully using TestRules though, but I'm not sure it's really easier in the end.
Hope this helped !
newbie here...thanks for your patience. I'm interested in writing a test class for the following controller, but not sure where to begin:
public class savecontroller
{
private final Emp__c emps;
public savecontroller(ApexPages.StandardController controller)
{
this.emps= (Emp__c)controller.getRecord();
}
public void autosave()
{
upsert emps;
}
}
Thank you
Your code is a little bit strange... From this part:
public savecontroller(ApexPages.StandardController controller)
it looks like your controller is not really a "controller", but more like an extension of a standard controller for Emp__c object. I know, it doesn't affect anythingin your post (except maybe semantics), BUT (!) it does have an affect on how you write your test class. Since this is an extension, test class would look something like this:
#isTest
public class saveconttroller_test {
public static Emp__c test_emp; // declaration
static {
test_emp = new Emp__c();
insert test_emp; //since you have upsert you can leave this out
}
static testMethod void testsavecotroller() {
Test.startTest();
//in the next two lines we contruct standard controller and the extension
ApexPages.StandardController sc = new ApexPages.StandardController(test_emp);
savecontroller ext = new savecontroller(sc);
ext.autosave();
Test.stopTest();
}
}
Now, let me point out a few things... first, as I'm sure you know, test should cover as much code as possible. SF requires 75%, but the closer you get to 100% the better. But (!), you should always include something to assert if your method is doing what it is suppose to be doing. For example in your case, i would change method autosave() like this:
public PageReference autosave()
{
try {
upsert emps;
return new ApexPages.StandardController(test_emp).view();
} catch(Exception e) {
return null;
}
}
By doing so, you can include System.assertEquals(ref1, ref2); in your test class, wher ref1 is reference you would expect (if the upsertion was successful this would be test_emp page reference) and ref2 would be the reference you actually get from the test.
Second thing is using static method in the test. Whatever you write in this method will always execute on Test.startTest(); call.
Hope this helps you! :)
Cheers, G.
What I have to do:
I have to test my spring mvc with JMockit. I need to do two things:
Redefine MyService.doService method
Check how many times redefined MyService.doService method is called
What the problem:
To cope with the first item, I should use MockUp; to cope with the second item I should use #Mocked MyService. As I understand this two approaches are overriding each other.
My questions:
How to override MyService.doService method and simultaneously check how many times it was invoked?
Is it possible to avoid mixing a behaviour & state based testing approaches in my case?
My code:
#WebAppConfiguration
#ContextConfiguration(locations = "classpath:ctx/persistenceContextTest.xml")
#RunWith(SpringJUnit4ClassRunner.class)
public class MyControllerTest extends AbstractContextControllerTests {
private MockMvc mockMvc;
#Autowired
protected WebApplicationContext wac;
#Mocked()
private MyServiceImpl myServiceMock;
#BeforeClass
public static void beforeClass() {
new MockUp<MyServiceImpl>() {
#SuppressWarnings("unused")
#Mock
public List<Object> doService() {
return null;
}
};
}
#Before
public void setUp() throws Exception {
this.mockMvc = webAppContextSetup(this.wac).build();
}
#Test
public void sendRedirect() throws Exception {
mockMvc.perform(get("/doService.html"))
.andExpect(model().attribute("positions", null));
new Verifications() {
{
myServiceMock.doService();
times = 1;
}
};
}
}
I don't know what gave you the impression that you "should use" MockUp for something, while using #Mocked for something else in the same test.
In fact, you can use either one of these two APIs, since they are both very capable. Normally, though, only one or the other is used in a given test (or test class), not both.
To verify how many invocations occurred to a given mocked method, you can use the "invocations/minInvocations/maxInvocations" attributes of the #Mock annotation when using a MockUp; or the "times/minTimes/maxTimes" fields when using #Mocked. Choose whichever one best satisfies your needs and testing style. For example tests, check out the JMockit documentation.
public class A
{
public String getText()
{
Marker.start();
...
...
Marker.end();
}
}
public class Marker
{
public static void start()
{
long now = System.currentTimeMillis;
}
public static void end()
{
long now = System.currentTimeMillis;
}
}
I want to use JPDA (Java Platform Debugger Architecture) to detect the occurrence of Marker.start() and Marker.end() from external application. However I think the code may be optimized / eliminated away by JVM. How to prevent dead code being optimized by JVM?
You could for example create a fake int variable somewhere in the class Marker and increment/decrement its value in the start() and end() methods. I don't think any optimizer could remove an instance field from a class even if the value is not used anywhere. After all, someone could always inject new agent code into the JVM and ask for the value. This means calls to start() and stop() shouldn't get optimized out, either.