I'm using rest-assured for integration testing on my endpoints. One of the endpoints has a dependency to another resource (it calls another API conditionally). Is there a way for me to stub out the API call so I can write a test for that case?
interface IDataProvider {
string RetrieveData();
}
class StandardDataProvider : IDataProvider {
public string RetrieveData(){
// call to API
}
}
class Program {
private IDataProvider _dataProvider;
public Program(IDataProvider provider = null) {
_dataProvider = provider ?? new StandardProvider();
}
public void MethodToTest(){
var data = _dataProvider.RetrieveData();
// do your thing
}
}
In the tests you can mock the data by creating your own IDataProvider object and working with its data.
class TestDataProvider : IDataProvider {
public string RetrieveData(){
return "my own data";
}
}
class Test {
[TestMethod]
public void TestProgram(){
var obj = new Program(new TestDataProvider);
var result = obj.MethodToTest();
// asserts
}
}
Lets say your code calls endpointB internally via http, you can stub that api by using https://github.com/katta/fakerest or https://stubby4j.com .So when your code makes a call internally to the another api, it will hit these stubs, which will return a dummy response always. Hope this helps.
Related
I need to test a class that is using another interface as a dependency injection with a lambda Consumer.
#Builder
public class Interactor {
private final Gateway gateway;
void process(String message, Consumer<String> response){
gateway.process(message, uuid -> {
response.accept(uuid.toString());
});
}
}
The dependency is defined like so:
public interface Gateway {
void process(String message, Consumer<UUID> uuid);
}
How would I mock the Gateway so I can provide a UUID value response to my test?
This is what I have tried so far:
#Test
void whillReturnTheInjectedUUIDValueTest() {
UUID uuid = UUID.randomUUID();
Gateway gateway = Mockito.mock(Gateway.class);
Mockito.when(gateway.process("ignored", uuid1 -> {return uuid;}));
Interactor.builder().gateway(gateway).build().process("ignored", s -> {
Assertions.assertEquals(uuid.toString(), s);
});
}
How should I provide the return value to the consumer?
this one did the trick
#Test
void willReturnTheInjectedUUIDValueTest() {
UUID uuid = UUID.randomUUID();
Gateway gateway = Mockito.mock(Gateway.class);
doAnswer(ans -> {
Consumer<UUID> callback = (Consumer<UUID>) ans.getArgument(1);
callback.accept(uuid);
return null;
}).when(gateway).process(Mockito.any(String.class), Mockito.any(Consumer.class));
Interactor.builder().gateway(gateway).build().process("ignored", s -> {
Assertions.assertEquals(uuid.toString(), s);
});
}
This answer was the hint -> https://stackoverflow.com/a/47226374/148397
For now I ended up mocking my own inner class without Mockito.
class InteractorTest {
#Test
void whillReturnTheInjectedUUIDValueTest() {
UUID uuid = UUID.randomUUID();
Gateway gateway = GatewayMock.builder().value(uuid).build();
Interactor.builder().gateway(gateway).build().process("ignored", s -> {
Assertions.assertEquals(uuid.toString(), s);
});
}
#Builder
private static class GatewayMock implements Gateway {
private final UUID value;
#Override
public void process(String message, Consumer<UUID> uuid) {
uuid.accept(value);
}
}
}
What you want...
is to verify the result of the logic of Interactor#process, which takes a Consumer<String> and basically just calls Gateway#process with a Consumer<UUID> implementation that calls back to the Consumer<String> parameter.
Ideally you want to do this just by calling Interactor#process and verifying the call to the Consumer<String> you supply.
Your problem is...
that it is up to the implementator of Gateway to trigger the Consumer<UUID> (and consequently the Consumer<String>). So you need to inject an implementation of Gateway that does just that.
The solution is...
along the lines of the answer you provided (i.e. using a Fake Object instead of a Mock), unless there is a real implementation of Gateway in your production code that you can easily use instead (but I assume you'd be doing that already if that was the case).
Can you do it with Mockito? Sure, you can call methods on a mock object's method arguments, as shown in this answer: https://stackoverflow.com/a/16819818/775138 - but why would you go there if you can provide a sufficient Gateway implementation in a single line:
Gateway gw = (message, consumer) -> consumer.accept(uuid);
where uuid is the UUID instance that you constructed before. So no need to declare a static inner class just for this.
However...
there is an important issue with your assertion: if Interactor does nothing at all instead of calling the Gateway, the Consumer<String> you provide (containing the assertion) won't get triggered, so your test will pass! Just assign the value to a member variable of your test class, and assert on that outside the lambda.
I have such method in my service layer:
public Long calculateItemsCostInShoppingCart(Long shoppingCartId) {
List<Item> items = shoppingCartRepository.findAllItems(shoppingCartId);
Long cost = 0L;
for (Item item : items) {
cost += item.getPrice();
}
return cost;
}
And I need to test calculation of summary cost of all items in list. I was thought about mockito, but it didn't work out cause mockito just create stubs, I need real entrance data and result based on them. How can do it?
// create mock
ShoppingRepository mock = mock(ShoppingRepository.class);
// define return value for method findAllItems()
when(mock.findAllItems()).thenReturn(listOf(...));
Here is an example how you can test it with Mockito:
public class SomeCalculatorTest {
#Mock
private ShoppingCartRepository shoppingCartRepository;
#InjectMocks
private SomeCalculator someCalculator = new SomeCalculator();
#Before
public void setUp() {
initMocks(this);
}
#Test
public void testEmptyItemsList() {
when(shoppingCartRepository.findAllItems(any())).thenReturn(new ArrayList<>());
final Long result = someCalculator.calculateItemsCostInShoppingCart(1L);
assertThat(result, is(0L));
}
#Test
public void testOneItemInList() {
when(shoppingCartRepository.findAllItems(any())).thenReturn(Arrays.asList(new ItemImpl(25L)));
final Long result = someCalculator.calculateItemsCostInShoppingCart(1L);
assertThat(result, is(25L));
}
#Test
public void testTwoItemInList() {
when(shoppingCartRepository.findAllItems(any())).thenReturn(Arrays.asList(new ItemImpl(25L), new ItemImpl(12L)));
final Long result = someCalculator.calculateItemsCostInShoppingCart(1L);
assertThat(result, is(37L));
}
}
Assuming that you are developing a Java web application which runs on a application server another option might be to use Arquillian (http://arquillian.org/). In a nutshell, Arquillian is a framework which allows you to test you logic in environment it will run. But it might be some work to integrate Arquillian into your project. We are using Arquillian in several projects and it works well so far. Even the Persistence module which is an Alpha version works well.
And I need to test calculation of summary cost of all items in list.
In this case, you have to isolate the shoppingCartRepository dependency that doesn't perform any calculation.
I need real entrance data and result based on them. How can do it?
It describes an integration test. In this case, don't use Mockito.
To unit test :
You have to mock the dependency and you also need a way to set it in the instance of the class under test.
A constructor is often a fine way (let calling the class under test MyService):
public MyService(ShoppingCartRepository shoppingCartRepository){
this.shoppingCartRepository = shoppingCartRepository;
}
Then, in the test you should mock ShoppingCartRepository, record a behavior for findAllItems() and pass the mock in the constructor of MyService.
#Mock
private ShoppingCartRepository shoppingCartRepositoryMock;
#Test
public void calculateItemsCostInShoppingCart(){
Long cartId = Long.valueOf(123);
// set the dependency
MyService myService = new MyService(shoppingCartRepositoryMock);
// create the mock
Mockito.when(shoppingCartRepositoryMock.findAllItems(cartId))
.thenReturn(createMockedItems());
//action
Long actualCost = myService.calculateItemsCostInShoppingCart(cartId);
// assertion
Assert.assertEquals(expectedCost, actualCost);
}
private List<Item> createMockedItems() { ... }
You can use Rest assured library for test
get Rest assured response Object, and call method for method object of list.
#BeforeClass
public static void init() {
RestAssured.baseURI = "http://localhost";
RestAssured.port = 8080;
}
#Test
public void testUserRegistration() {
Response response =
RestAssured
.given()
.get(URL_LOGIN)
.then()
.assertThat()
.statusCode(200);
Assert.assertThat(200, Matchers.is(200));
Assert.assertThat(response.getStatusCode(), Matchers.is(200));
}
I need to validate request before different rpc methods being called with different validators.
So I implemented validators like
class BarRequestValidator {
public FooServiceError validate(BarRequest request) {
if (request.bar.length > 12) {
return FooServiceError.BAR_TOO_LONG;
} else {
return null;
}
}
}
and add a custom annotation before my rpc method
class FooService extends FooServiceGrpc.FooServiceImplBase {
#Validated(validator = BarRequestValidator.class)
public void bar(BarRequest request, StreamObserver<BarResponse> responseObserver) {
// Validator should be executed before this line, and returns error once validation fails.
assert(request.bar <= 12);
}
}
But I found that I can't find a way to get annotation information in gRPC ServerInterceptor. Is there any way to implement grpc request validation like this?
You can accomplish this without having the annotation at all, and just using a plain ServerInterceptor:
Server s = ServerBuilder.forPort(...)
.addService(ServerInterceptors.intercept(myService, myValidator))
...
private final class MyValidator implements ServerInterceptor {
ServerCall.Listener interceptCall(call, headers, next) {
ServerCall.Listener listener = next.startCall(call, headers);
if (call.getMethodDescriptor().getFullMethodName().equals("service/method")) {
listener = new SimpleForwardingServerCallListener(listener) {
#Override
void onMessage(request) {
validate(request);
}
}
}
return listener;
}
}
Note that I'm skipping most of the boilerplate here. When a request comes in, the interceptor gets it first and checks to see if its for the method it was expecting. If so, it does extra validation. In the generated code you can reference the existing MethodDescriptors rather than copying the name out like above.
I have foolowing class which I would like to mock:
BusineesLayer:
/**
* Created by Alexandr on 14.05.2016.
*/
public class BusineesLayer {
public OrderModel orderModel;
public DbService dbService;
...
public BusineesLayer(OrderModel orderModel,DbService dbService) {
this.orderModel = orderModel;
dbService = dbService;
}
public BusineesLayer() {
}
public boolean checkItemsInDb(List<Items> items) throws HandleOrderExeption {
...
return result
}
public boolean handleOrder() throws HandleOrderExeption {
checkItemsInDb(orderModel.getItemsList());
boolean res =dbService.addOrder(orderModel.getItemsList(),
orderModel.getCustumerName(),
countTotalSum(orderModel.getItemsList())
);
return res;
}
}
I would like to test hanldeOrder() method and in order to make it less excess insted of checkItemsinDb() inside invoke "true";
So, my test looks like this:
#Test
public void handleorderTest() {
...
BusineesLayer layer = Mockito.mock(BusineesLayer.class);
layer.dbService = busineesLayer.dbService;
layer.orderModel = busineesLayer.orderModel;
Mockito.when(layer.checkItemsInDb()).thenReturn(true);
boolean res = layer.handleOrder();
assertThat(res, equalTo(true));
}
but it always return false and doesn't go through handlOrder() at all
Is any ways to solve it? Or how can I refactor my code to test it?
You do not test mocks, you use mocks to help you test.
I think you've just become confused at how you are using mocks. Mocks allow us to simulate and can responses to objects we are testing. If you're testing the handleOrder method, then you should mock anything that interacts with that method, in this case DbService and OrderModel.
#Test
public void handleorderTest() {
BusineesLayer layer = new BusineesLayer(); //we are testing this!
DbService dbService = Mockito.mock(DbService.class);
OrderModel orderModel = Mockito.mock(OrderModel.class);
layer.dbService = dbService;
layer.orderModel = orderModel;
Mockito.when(orderModel.getItemsList()).thenReturn(new ArrayList<Items>());
Mockito.when(dbService.foo()).thenReturn(true);
//mock up multiple calls so your service will provide true
boolean res = layer.handleOrder();
assertThat(res, equalTo(true));
//repeat for false, and so on
}
If, however, you are trying to test the dbService call, then you should create a test for it without the business layer at all. The business layer doesn't depend on anything except calls to other methods, so whether you use those real objects or mocked versions of those objects, the functionality should be the same. The business logic only appears to fail if DBService or OrderModel break, so you would test service and model separately (without involving the business layer) to test those.
I am unit testing a Presenter class which connects to service and returns a token
When user receives a token from Async task which calls REst services, Home screen starts. If token is null error is shown
public void onSignInButtonClicked() {
String username = mSigninView.getUsername();
if (username.isEmpty()) {
mSigninView.showUsernameError(R.string.username_error);
return;
}
String password = mSigninView.getPassword();
if (password.isEmpty()) {
mSigninView.showPasswordError(R.string.password_error);
return;
}
String token = mSigninService.connectToRestServices(username, password);
if (token != null) {
mSigninView.startHomeActivity(token);
} else {
mSigninView.showLoginError(R.string.login_error);
}
}
For unit testing :
#Test
public void shouldStartHomeScreenWhenUsernameAndPasswordAreCorrect() throws Exception {
Mockito.when(mView.getUsername()).thenReturn("test#test.com");
Mockito.when(mView.getPassword()).thenReturn("test");
Mockito.when(mService.connectToRestServices("test#test.com", "test")).thenReturn("test");
mPresenter.onSignInButtonClicked();
Mockito.verify(mView).startHomeActivity("test");
}
Error while testing
Wanted but not invoked:
signin_View.startHomeActivity("test");
-> at com.ssd.cypress.uimobile.SigninPresenterTest.shouldStartHomeScreenWhenUsernameAndPasswordAreCorrect(SigninPresenterTest.java:72)
In the code
String token = mSigninService.connectToRestServices(username, password);
It connects to concrete class and token is null. Is there a way to mock this connectToService so that it returns SomeValue.
Your mock service collaborator mService is never called during the test because it's not passed into or injected into the class under test. Based on your comments, I think you realize this.
To restate your comments as I understand them, you want to use the mock of a collaborator - an instance of Sign_in_service - but you can't do it because the collaborator is created by rather than passed into your class under test - SigninPresenter.
The problem is your constructor of SigninPresenter, which should not be responsible for creating a collaborator. It seems like you own the code in question, so you can change the design.
I suggest you replace the SigninPresenter constructor with the following:
public static SigninPresenter createSigninPresenterWithService(Signin_View view) {
return new SigninPresenter(view, new Sign_in_service());
}
protected SigninPresenter(Signin_View view, Sign_in_service service) {
mSigninView = view;
mSigninService = service;
}
For your test, you can call the constructor and pass in a mock of the service to initialize mPresenter, that is: mPresenter = new SignInPresenter(mView, mService). In your production code which currently calls the constructor of SigninPresenter, you can replace the constructor call new SigninPresenter(view) with a call to the static factory method createSigninPresenterWithService(view).