Donnerstag, 17. Mai 2018

spyOn static Methods in jasmine tests

If you want to spy on a static method within your jasmine tests, you could do a simple spy like


beforeAll(async() =>{
  spyOn(UserService, "staticMethod").and.returnValue(true);
});


I'll tend to do this within beforeAll to avoid having problems when doing this in beforeEach. Within beforeEach you might end up in error messages like 

Error: <spyOn> : staticMethod has already been spied upon
    at <Jasmine>
    at UserContext.<anonymous> src/app/shared/components/result-detail/sample.component.spec.ts:74:5)
    at ZoneDelegate.webpackJsonp../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke node_modules/zone.js/dist/zone.js:388:1)
    at ProxyZoneSpec.webpackJsonp../node_modules/zone.js/dist/proxy.js.ProxyZoneSpec.onInvoke node_modules/zone.js/dist/proxy.js:128:1)
    at ZoneDelegate.webpackJsonp../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke node_modules/zone.js/dist/zone.js:387:1)
    at Zone.webpackJsonp../node_modules/zone.js/dist/zone.js.Zone.run node_modules/zone.js/dist/zone.js:138:1)
    at runInTestZone node_modules/zone.js/dist/jasmine-patch.js:145:1)
    at UserContext.<anonymous> node_modules/zone.js/dist/jasmine-patch.js:160:1)

Jasmine runner TypeError 'next' in Angular5 Tests

I stumbled upon an error, which a karma runner gives me in some of our jasmine tests:

TypeError: Cannot read property 'next' of undefined
    at <Jasmine>
    at Function.continuer node_modules/q/q.js:1278:1)
    at UserContext.<anonymous> node_modules/q/q.js:1305:1)
    at ZoneDelegate.webpackJsonp../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke node_modules/zone.js/dist/zone.js:388:1)
    at ProxyZoneSpec.webpackJsonp../node_modules/zone.js/dist/proxy.js.ProxyZoneSpec.onInvoke node_modules/zone.js/dist/proxy.js:128:1)
    at ZoneDelegate.webpackJsonp../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke node_modules/zone.js/dist/zone.js:387:1)
    at Zone.webpackJsonp../node_modules/zone.js/dist/zone.js.Zone.run node_modules/zone.js/dist/zone.js:138:1)
    at runInTestZone node_modules/zone.js/dist/jasmine-patch.js:145:1)
    at UserContext.<anonymous> node_modules/zone.js/dist/jasmine-patch.js:160:1)
    at <Jasmine>

I couldn't find something wrong with the test itself, but I noticed an strange import:

[async] from "q";

This was the reason for the strange error message. Correct import ist

[async] from "@angular/core/testing";

Sonntag, 4. März 2018

How to transform a Array to a map in Javascript/Typescript

This might be an easy one but I thought it is worth saving it here.
Let's assume you want to create a HashMap in typescript or javascript with http status codes and corresponding messages. This might be useful within a frontend error handler.
Here is your error-messages.json


[
  {"code": 403,    "message": "You are not permitted to use this action."  },
  {"code": 400,    "message": "The request was incomplete or wrong."  }, 
  {"code": 500,    "message": "A general error has occured."  }
]

here is how you could use it in your code:


// Map with error codes
  errorCodeMapping: Map<number, string> = new Map<number, string>();
// read error codes as json map
let array = Array.from(require("./error-messages.json"));
// map array to errorCode Map
this.errorCodeMapping = new Map(array.map((i: ErrorMessage): [number, string] => [i.code, i.message]));
// get a message for an error code
let msg: string = this.errorCodeMapping.get(403);

Karma runner Disconnected (1 times), because no message in 10000 ms.

We are using karma as the test runner within our angular 5 application. It does a pretty good job when it's time to build regression tests for our frontend. After a while using it I noticed an error during the coverage test run.

> xxxx-frontend@0.0.0 coverage C:\workspaces\andre\Intellij\xxxx\frontend
> ng test --cc --single-run
05 03 2018 08:04:47.006:INFO [karma]: Karma v2.0.0 server started at http://0.0.0.0:9876/
05 03 2018 08:04:47.009:INFO [launcher]: Launching browser Chrome with unlimited concurrency
05 03 2018 08:04:47.016:INFO [launcher]: Starting browser Chrome
05 03 2018 08:05:06.109:INFO [Chrome 64.0.3282 (Windows 7.0.0)]: Connected on socket fwQIL6cCt7q6VM0sAAAA with id 76897689
05 03 2018 08:05:12.110:WARN [Chrome 64.0.3282 (Windows 7.0.0)]: Disconnected (1 times), because no message in 6000 ms.
Chrome 64.0.3282 (Windows 7.0.0) ERROR
 
Disconnected, because no message in 10000 ms.

Sometimes this happens because we got an error wihtin the test cases. After writing a lot of test cases I noticed that the execution of all test cases took about 11 sec. So I increased our timeout with setting

browserNoActivityTimeout: 60000,

within the karma.conf. That fixed the issue.

Mittwoch, 5. Juli 2017

How to organize imports in Intellij when saving a file

I always forget this nice plugin. Do the following if you want your Intellij to organize imports or reformat code while saving a file

  1. Install Plugin "Save Actions" within your IntelliJ
  2. Perform your settings within the "save actions" settings page

Mittwoch, 17. Mai 2017

Where are the ear or war files stored in a jboss container?

I was searching where jboss stores an ear or war files once you deployed it via the cli cmd line. Here is my finding on that:

  • The uploaded war or ear ist stored within a file called $jboss.server.base.dir/standalone/data/content/xx/xxyyyyyyyyy/content
  • xx is a two char directory name within the default data folder
  • yyyyyyyyyyy is a hash value of your ear or war
  • You will find the xxyyyyyyy key as the sha1 value of your deployed ear or war within your standalone.xml config under the deployment section
Within the $jboss.server.base.dir/standalone/tmp you might find the cache of our currently running jboss. If you delete tmp after stopping jboss it will reinstall the ingredients from data. If you delete data you are screwed and you have to remove the ear or war entries from your standalone.xml or start jboss with --admin-only to redeploy the war or ears with the console.


Dienstag, 7. März 2017

Take care when using @Injectmocks

Well @Injectmocks is nice and evil in one tag. Assume we have this service 

@Service
public class SampleService {
    private final Logger LOG = Logger.getLogger(SampleService.class.getName());

    @Autowired
    private SampleDependency1   dependency1;

    public Long sampleMethod() {
        LOG.info("Calling sampleMethod");
        Long l = dependency1.calculateValue();
        LOG.info("l = " + l);
        return  l;
    }
}
and the corresponding test
@RunWith(SpringRunner.class)
@SpringBootTest
public class InjectmocksApplicationTests {
    @Mock
    private SampleDependency1 dependency1;

    @InjectMocks
    private SampleService service = new SampleService();

    @Test
    public void contextLoads() {
        when(dependency1.calculateValue()).thenReturn(null);
        final Long l = service.sampleMethod();
        Assert.isNull(l, "well l should be null");
    }
}

Ok, should work and will call our service with the injected mock for dependency1. Now lets add a second dependency like this:
@Service
public class SampleService {
    private final Logger LOG = Logger.getLogger(SampleService.class.getName());

    @Autowired
    private SampleDependency1   dependency1;

    @Autowired
    private SampleDependency2   dependency2;

    public Long sampleMethod() {
        LOG.info("Calling sampleMethod");
        Long l = dependency1.calculateValue();
        l= dependency2.calculateValue();
        LOG.info("l = " + l);
        return  l;
    }
This will compile, but running your test will result in 
java.lang.NullPointerException at net.kambrium.example.SampleService.sampleMethod(SampleService.java:23)
because you forgot to add dependency2 to your test class. To avoid this do
1. Use constructor wiring for your dependencies
2. Use @InjectMocks wisely and go searching on your tests for usage of the service you change and adjust the test cases
I personally prefer 1. as it always starts complaining at compile time. If your are using checkstyle you will see this warning, when using field injection:
Spring Team recommends: "Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies"