Advice on Mocking System Calls

How to Mock Linux System Calls in C

In general, you want to create a wrapper for each system call you're testing. A good way to do this and make your code easy to follow, would be just to use the ld option: --wrap. This lets you swap out symbols at build time without having to re-write your code to use your wrapper functions in place of the real libc functions.

Additionally, you could use LD_PRELOAD to override libc system call wrapper functions, like how rootkit/virus writers do, but there is more work involved than just using --wrap functionality.

Finally, you could utilize a unit test framework (i.e. CUnit) in your wrapper functions, simplifying your testing.

Mocking a system dependencies

So, I thought about using a Mock server for each of my dependencies and discovered pact.io. As I understand, Pact allows me to write contracts and start a mock server so my system can then run HTTP requests against the mock server. Pact also allows me to give the contract to the service provider so it can also run the contract against the real app to see if it really works.

Yes, that's correct. Pact can probably be considered as a unit testing tool for your API client, that uses contract testing to ensure the mocks are valid.

If you're using Pact just for mocking, you're missing out on all of the key benefits though.

Using Pact at such a high level test is considered bad practice, and as you can see, is difficult to do (you're working against the way it is intended to be used).

I would worry less about overlapping tests (end-to-end tests will always double up with other layers testing by design), and concern yourself more about ensuring each of the API contracts are covered by Pact. These tests will run much faster, are more precise in what the test and are less flakey.

This way, you can reduce the scope of your end-to-end BDD scenarios to the key ones and that should reduce the maintenance cost.

Mocking Chained calls in Concrete Class Mockito

Mockito is not able to mock out final classes. There are a few ways to get around this.

1) In MyAbstractClass consider not referencing a final class, and instead reference an interface or abstract class that MyFinalClass implements (or extends). So lets say that MyFinalClass implements an interface called MyGettableApi. Then MyAbstractClass would look like this.

 public abstract class MyAbstractClass{

@Autowired
private MyGettableApi gettableService;

//concrete method
protected Object myConcreteMethod(String name){
try{
Object b = gettableService.getObject(name);
return b;
} catch(MyException e){
LOGGER.log("ERROR THROWN" + e);
}
}

}

public final class MyFinalClass implements MyGettableApi {

@Override
public Object getObject(String name) throws MyException{
**** HAS NOT YET BEEN IMPLEMENTED ****
return null;
}

}

public interface MyGettableApi {
public Object getObject(String name);
}

Now in your test code you can mock out MyGettableApi, since it is not final, without a problem.

    @Mock
MyGettableApi myFinalClass;

2) Another way around this is wrap the call to myFinalClass.getObject(name); wrapped in another method.

public abstract class MyAbstractClass{

@Autowired
private MyFinalClass myFinalClass;

//concrete method
protected Object myConcreteMethod(String name){
try{
Object b = myGetObjectWrapperMethod(name);
return b;
} catch(MyException e){
LOGGER.log("ERROR THROWN" + e);
}
}

Object myGetObjectWrapperMethod(String name) {
return myFinalClass.getObject(name);
}

}

Now in your test code you would @Spy the instance of MyAbstractClass that is being tested.

@InjectMocks
@Spy
ExampleConcreteClass exampleConcreteClass;

then you can mock out our new wrapper method.

doThrow(new MyException()).when(exampleConcreteClass).myGetObjectWrapperMethod(name);

How do I mock call method from testable class?

You can do this using a spy, like explained here: https://static.javadoc.io/org.mockito/mockito-core/2.7.17/org/mockito/Mockito.html#13

Example:

@Test
public void testMethod1() throws Exception {
SomeClass someClass = new SomeClass();
SomeClass spy = Mockito.spy(someClass);
Mockito.when(spy.getData()).thenReturn(Arrays.asList("blaat", "blabla"));
spy.method1();
}

This will return a List of "blaat" and "blabla" which can be used by the logic in your method1.

Mock that a method call was attempted during unit test, but do not actually call it

Spies are ugly. If you partially mock your class under test, you easily to get confused about what is mocked and what is really tested. Mockito's Javadoc explicitly warns against partial mocking.

Better to refactor your code so you can test it cleanly. Extract doSomething() into a new class:

public class SomethingDoer {
public void doSomething(int a, int b) {
// code that you do not want to be executed during a unit test
}
}

Changed MyClass:

public class MyClass {
private final SomethingDoer somethingDoer;

public MyClass(SomethingDoer somethingDoer) {
this.somethingDoer = somethingDoer;
}

public void myMethod() {
int a = [do some logic]
int b = [do some logic];
somethingDoer.doSomething(a, b);

a = [do some logic];
b = [do some logic];
somethingDoer.doSomething(a, b);
}
}

Test:

@Test
public void test() {
SomethingDoer somethingDoer = mock(SomethingDoer.class);
MyClass myClass = new MyClass(somethingDoer);
myClass.myMethod();
verify(somethingDoer).doSomething(17, 33);
verify(somethingDoer).doSomething(9, 18);
}


Related Topics



Leave a reply



Submit