Author Archives: Niklas - Page 17

Git: Squash your commits

When working on a pull-request that keeps getting updated with commit after commit you sometimes need too squash some commits to get a nicer history

I’m here going to show you one way to do just that using the interactive view of git rebase

git log --pretty=oneline

This could look something like this:

5d870be Added submit button
56f962c Added knockoutjs logic
5640719 Merge pull request #1148
5015685 Set encoding on property file
4ec2f9c Updated test database scripts
567cd41 Checkstyle fix
980be70 Added border to form
405fc82 Resolved conflict with main
52eb187 Fixed login div border
fc2b99b Fixed bugg with form validation
2f8f126 Updated JQuery version
0acd0fe Fixed flow test
4dfb2dd Added form validation test
3cc1247 Added xml parser

Now we look for a good place to squash. Let’s say that we for example want to squash row 1 to 5. To start the process we run:

git rebase -i 567cd41

We here choose the hash of the commit just below the one where we want to squash from. This will bring up your favorite editor (in my case VIM) where you can mark which commits you want to keep (‘pick’) and which ones you woulkd like to squash (‘squash’). You can even rearange you commits here – just make sure to rearange the hashes too 🙂 . Note! The order of commits in the editor is reversed. Older above and newer below

pick 567cd41 Checkstyle fix
squash 4ec2f9c Updated test database scripts
squash 5015685 Set encoding on property file
squash 5640719 Merge pull request #1148
squash 56f962c Added knockoutjs logic
squash 5d870be Added submit button

# Rebase 567cd41..5d870be onto 5015685 (6 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

After you have made your changes you save and quit, and the rebasing operation starts.
This process can find conflicts that needs to be resolved, like any other rebase. You will also be asked to set the commit message of the squash. This messages will contain all of the commit messages so here is a good oppertunity to make them pretty and understandable 😉

NOTE! This solution might not play nice when there are merge commits present!

Tested on Git v2.24.3 and OSX 10.15.6

Chrome web driver headless VM option

This small post will show how to set the chromedriver in non-headless mode using a WM option instead of e.g. a driver option. This is sometimes useful when running tests in an IDE like IntelliJ

-Dwebdriver.chrome.headless=false

Tested on Chrome webdriver v78.0.3904.70 and IntelliJ v2019.3

Mock a dependency in system under test in a Spring Boot application with Mockito

System under test class example:

import my.special.sclient
...

class App {
  Sclient sclient = getNewSclient();
  
  public String methodA(String input) { 
    return sclient.getValue(input);
  }

  protected Sclient getNewSclient() {
    return new Sclient();
  }
}

Test class example:

import org.mockito.InjectMocks;
import org.mockito.Spy;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
...

class Test {
  @Spy
  @InjectMocks
  private App sut;

  @Mock
  Sclient mockClient;

  @BeforeMethod
  public void setUp() {
    MockitoAnnotations.initMocks(this);
    when(sut.getNewSclient()).thenReturn(mockClient);
    when(mockClient.getValue("bar")).thenReturn("foo");
  }

  @Test
  public void myTest() {
    String value = sut.getValue("bar");
    assertThat(value, is("foo"));
  }
}

So, how does this work? I will try to explain below:

1. First we need to be able to intercept the ‘sclient’ in the App class. This is done by simply creating a ‘getNewSclient()’ function and then mock it in the Test class so that we instead can use a mocked version of it.

2. Next we need to setup our test class. Here we need both a @Spy and @InjectMocks on the App object. We also need a mocked instance of the ‘sclient’ we are going to use

3. Now we need to set upp the desired behaviour of our mocked ‘sclient’. We set it so that if you input “bar” you should get “foo” back

4. Done!

Tested on Java v1.8.0_252, Mockito v3.3.3, TestNG v6.11 and Spring Boot v2.2.4