-1

When I write unit tests should I create one or more test methods for each and every method that I create in the source file? If the method calls 3 other methods , should response of all those methods be mocked?

Punter Vicky
  • 15,954
  • 56
  • 188
  • 315
  • Regarding one or more test methods: see https://stackoverflow.com/a/57616196/5747415 (answer to second part of question). Regarding mocks: see https://stackoverflow.com/a/56102108/5747415 – Dirk Herrmann Sep 18 '19 at 21:09

3 Answers3

1

Can those 3 other methods be called from other functions?

If yes then you'd need to test them out individually.

If no then likely those methods should be marked as private and just test your public interface ie the one which calls all three. If that test works then it means your private API is written correct.

But it's usually easier to break/fail a test at a smaller more focused function than a high level function.

mfaani
  • 33,269
  • 19
  • 164
  • 293
  • I’m writing a python module. This is a backend process within a AWS lambda function which calls the lambda handler. Lambda handler then calls another function which in turn calls 3 functions. I was trying to break down the logic into their own functions to test them independently. I was assuming that if I test the functions independently, i can mock the responses of these functions in the calling function – Punter Vicky Sep 18 '19 at 18:57
  • I think I've already addressed you concern. If those functions can only be called from that single high level function then you don't really need to unit test the rest. But then again are you sure you're covering every case? Working on smaller functions is easier. In theory you wouldn't need to. But in reality you more sure of your test cases. tl;dr from my perspective, there isn't a clear cut answer. Use your common sense. – mfaani Sep 18 '19 at 18:59
1

As a primer, I would say yes, you should add at least one test for each public method (with the experience you will find some methods are not worthy or if they already tested by other tests).

Regarding mocks, I would just mock the minimum in order to make the method under test work as expected. Too much mocking might smell of poor design.

Gonzalo Matheu
  • 8,984
  • 5
  • 35
  • 58
1

I'm sure you will get many varying opinions on this. But in my experience, generally you would have at least 1 test for each public method. I start with happy path and then explore the edge cases and error scenarios. I mock out only external calls, private methods can be tested via the public methods, or if complex, I either extract them to a delegate that can be tested independently or I loosen the accessibility (i.e. protected in Java) so that the method can be tested directly (judgement call based on sensitivity/design considerations).

In Java / JUnit / Mockito:

public class SystemUnderTest {
  private SomeDependency dependency;

  public Response doSomething(String parameter) {
    String foo = dependency.doSomethingForMe(parameter);
    String bar = privateMethod(foo);
    return new Response(bar);
  }

  private String privateMethod(String in) {
    if("foo".equals(in)) return "bar";
    else return "baz";
  }

  protected String complexNonPublicMethod(String a, String b, String c) {
    .. does complicated things ..
  }
}
public class SystemUnderTestTest { // Pardon the ugly name
  @Mock
  private SomeDependency dependencyMock;

  @InjectMocks
  private SystemUnderTest sut;

  @Test
  public void doSomething_happyPath() {
    String input = "input";
    String mockFoo = "foo";

    when(dependencyMock.doSomethingForMe(input)).thenReturn(mockFoo);

    String expected = new Response("bar");
    String actual = sut.doSomething();

    assertEquals(expected, actual); // JUnit syntax OR
    assertThat(actual, is(expected)); // Hamcrest syntax (which I prefer)

    verify(dependencyMock, times(1)).doSomethingForMe(input);
    verifyNoMoreInteractions(dependencyMock);
  }

  @Test
  public void doSomething_inputIsNull() {
    String input = null;
    String mockFoo = "foo";

    when(dependencyMock.doSomethingForMe(input)).thenThrow(new NullPointerException("Input is required!"));

    try {
      sut.doSomething();
      fail("Expected exception not thrown.");
    } catch (Exception e) {
       assertThat(e instanceof NullPointerException.class, is(true));
       assertThat(e.getMessage, is("Input is required!"));
    }
  }

  // Protected accessibility frees you from having to test this via some other public method
  @Test
  public void complexNonPublicMethod_happyPath() {
    String expected = <whatever>;
    String actual = sut.complexNonPublicMethod(a, b, c);
    assertThat(actual, is(expected));
  }

  // Protected accessibility frees you from having to test this via some other public method
  @Test
  public void complexNonPublicMethod_NullInput_A() {
    String expected = <whatever>;
    String actual = sut.complexNonPublicMethod(null, b, c);
    assertThat(actual, is(expected));
  }

  // Protected accessibility frees you from having to test this via some other public method
  @Test
  public void complexNonPublicMethod_NullInput_B() {
    String expected = <whatever>;
    String actual = sut.complexNonPublicMethod(a, null, c);
    assertThat(actual, is(expected));
  }

.. etc ..
}

Good Luck!

Marquee
  • 1,776
  • 20
  • 21