spring boot for unit test only - unit-testing

i have an application that use classic spring configuration with xml, it is possible to use spring boot for only unit test ?
like this:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
#ContextConfiguration(locations = { "classpath:security-context.xml",
"classpath:persistence-context-test.xml", "classpath:core-context.xml",
"classpath:web-context.xml" })
#EnableAutoConfiguration
public class SampleTomcatApplicationTests {
#Test
public void testHome() {
}
}

ok its easy just create a class with spring boot main method like this:
#SpringBootApplication
#ImportResource(locations = { "classpath:security-context.xml", "classpath:persistence-context-test.xml", "classpath:core-context.xml", "classpath:web-context.xml" })
public class SimpleBootCxfSystemTestApplication {
/**
* The main method.
*
* #param args
* the arguments
*/
public static void main(String[] args) {
SpringApplication.run(SimpleBootCxfSystemTestApplication.class, args);
}
}
and change the class test like this:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = SimpleBootCxfSystemTestApplication.class)
#WebIntegrationTest("server.port:8080")
#ActiveProfiles("test")
#WithUserDetails(value = "testUser", userDetailsServiceBeanName = "utilisateurService")
public class SampleTomcatApplicationTests {
//autowired
...
//test
}

Related

Integrated Unit Testing is not running in ASP.NET core MVC/Web API

I am developing a web API using ASP.Net core. I am doing integrated testing to my project. I am following this link, https://koukia.ca/integration-testing-in-asp-net-core-2-0-51d14ede3968. This is my code.
I have the controller to be tested in the thegoodyard.api project.
namespace thegoodyard.api.Controllers
{
[Produces("application/json")]
[Route("api/category")]
public class CategoryController: Controller
{
[HttpGet("details/{id}")]
public string GetCategory(int id = 0)
{
return "This is the message: " + id.ToString();
}
}
}
I added a new unit test project called thegoodyard.tests to the solution. I added a TestServerFixture class with the following definition
namespace thegoodyard.tests
{
public class TestServerFixture : IDisposable
{
private readonly TestServer _testServer;
public HttpClient Client { get; }
public TestServerFixture()
{
var builder = new WebHostBuilder()
.UseContentRoot(GetContentRootPath())
.UseEnvironment("Development")
.UseStartup<Startup>(); // Uses Start up class from your API Host project to configure the test server
_testServer = new TestServer(builder);
Client = _testServer.CreateClient();
}
private string GetContentRootPath()
{
var testProjectPath = PlatformServices.Default.Application.ApplicationBasePath;
var relativePathToHostProject = #"..\..\..\..\..\..\thegoodyard.api";
return Path.Combine(testProjectPath, relativePathToHostProject);
}
public void Dispose()
{
Client.Dispose();
_testServer.Dispose();
}
}
}
Then again in the test project, I created a new class called, CategoryControllerTests with the following definition.
namespace thegoodyard.tests
{
public class CategoryControllerTests: IClassFixture<TestServerFixture>
{
private readonly TestServerFixture _fixture;
public CategoryControllerTests(TestServerFixture fixture)
{
_fixture = fixture;
}
[Fact]
public async Task GetCategoryDetai()
{
var response = await _fixture.Client.GetAsync("api/category/details/3");
response.EnsureSuccessStatusCode();
var responseString = await response.Content.ReadAsStringAsync();
bool containMessage = false; //responseString.Contains("This is the message: 3"); - I commented on purpose to make the test fails.
Assert.True(containMessage);
}
}
}
Then I right on the test method and clicked run tests in the option to run the test. But none of the tests was run. This is the output.
What is missing in my code? How can I get my integrated test running?
Please check following NuGet packages in your project:
Microsoft.AspNetCore.TestHost
Microsoft.NET.Test.Sdk
xunit
xunit.runner.visualstudio
Perhaps there's a build error that's preventing the project from being compiled. There's really not enough information here to say for sure. Rebuild your solution, and ensure there's no errors.
Aside from that, you can remove some variables by reducing the test code needed. ASP.NET Core includes a WebApplicationFactory<TEntryPoint> fixture out of the box for bootstrapping a test server. You can therefore change your test code to just:
public class CategoryControllerTests: IClassFixture<WebApplicationFactory<Startup>>
{
private readonly WebApplicationFactory<Startup> _factory;
public CategoryControllerTests(WebApplicationFactory<Startup> factory)
{
_factory = factory;
}
[Fact]
public async Task GetCategoryDetail()
{
var client = _factory.CreateClient();
var response = await client.GetAsync("api/category/details/3");
...
See the documentation for additional information and more advanced scenarios.
This way works fine for xUnit based intergration tests, which use Startup configuration. the code blow also demonstrates how to override some settings in appSetting.json to specific values for testing, as well as how to access to DI services.
using System;
using System.Net.Http;
using MyNamespace.Web;
using MyNamespace.Services;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace MyNamespace.Tests
{
public class TestServerDependent : IDisposable
{
private readonly TestServerFixture _fixture;
public TestServer TestServer => _fixture.Server;
public HttpClient Client => _fixture.Client;
public TestServerDependent()
{
_fixture = new TestServerFixture();
var myService = GetService<IMyService>();
// myService.PerformAnyPreparationsForTests();
}
protected TService GetService<TService>()
where TService : class
{
return _fixture.GetService<TService>();
}
public void Dispose()
{
_fixture?.Dispose();
}
}
public class TestServerFixture : IDisposable
{
public TestServer Server { get; }
public HttpClient Client { get; }
public TestServerFixture()
{
var hostBuilder = WebHost.CreateDefaultBuilder()
.ConfigureAppConfiguration(
(builderContext, config) =>
{
var env = builderContext.HostingEnvironment;
config
.AddJsonFile("appsettings.json", optional: false)
.AddJsonFile("appsettings.Testing.json", optional: false,
reloadOnChange: true);
})
.ConfigureLogging(
(hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
logging.AddDebug();
})
.UseStartup<Startup>();
Server = new TestServer(hostBuilder);
Client = Server.CreateClient();
}
public void Dispose()
{
Server.Dispose();
Client.Dispose();
}
public TService GetService<TService>()
where TService : class
{
return Server?.Host?.Services?.GetService(typeof(TService)) as TService;
}
}
}
How the simple integration test might look like with the described above:
using System.Net;
using Xunit;
namespace MyNamespace.Tests
{
public class SimpleIntegrationTest : TestServerDependent
{
[Fact]
public void RedirectToLoginPage()
{
var httpResponseMessage = Client.GetAsync("/").Result;
// Smoke test to make sure you are redirected (to Login page for instance)
Assert.Equal(HttpStatusCode.Redirect, httpResponseMessage.StatusCode);
}
}
}

how to resolve dependency injection in xunit?

I have a problem in creating a test unit using xunit for my services that use dependency injection.
How can i send my dependency to test class?
[Fact]
public async Task GetAllRequestsHavePagingNoFilterNoSortAsync()
{
requestViewModel.RemotePaging = true;
requestViewModel.PageSize = 10;
requestViewModel.Page = 1;
var x = await requestService.GetAsync(requestViewModel);
Assert.NotNull(x);
Assert.True(x.PageCount == requestViewModel.PageSize);
}
You need to mock the dependencies using another library, the most popular one is Moq
So, assuming you have a class like this with a dependency injected:
public class ScrapedJobService : IScrapedJobService
{
private readonly IScrapedJobRepository _scrapedJobRepository;
public ScrapedJobService(IScrapedJobRepository scrapedJobRepository)
{
_scrapedJobRepository = scrapedJobRepository;
}
public WorkingPlace FindWorkingPlace(string title)
{
...
}
}
You need mock that dependency like this:
using Moq;
using Xunit;
private readonly ScrapedJobService _sut;
private readonly Mock<IScrapedJobRepository> _scrapedJobRepo = new Mock<IScrapedJobRepository>();
public ScrapedJobServiceTest()
{
_sut = new ScrapedJobService(_scrapedJobRepo.Object);
}
[Fact]
public void Test()
{
var result = _sut.FindWorkingPlace("Remote");
Assert.Equal(WorkingPlace.Remote, result);
}
Create a startup.cs file then map the dbcontext and the irepositoryDB specification to RepositoryDB concrete class. Dependency inject the IrepositoryDB in the xunit class constructor.
namespace XUnitTestProject1
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
var configuration = new ConfigurationBuilder()
.SetBasePath(System.IO.Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.Development.json", false, true)
.Build();
services.AddControllers();
var connectionString = configuration.GetConnectionString("My_DbCoreConnectionString");
services.AddDbContext<MY_DB_Context>(options2 => options2.UseSqlServer(connectionString));
services.AddTransient<IRepositoryDB, RepositoryDB>();
}
}
}
XUnit
public class UnitTest1
{
private readonly IRepositoryDB _repository;
public UnitTest1(IRepositoryDB repository)
{
_repository = repository;
}
public async Task GetItems(long id)
{
IList<myItem> list= await _repository.GetItems(id);
Assert.True(list.Count>0);
}

Run Spring Boot Unit tests ignoring CommandLineRunner

I'm trying to write spring boot unit tests but have some problems with CommandLineRunner which runs entire app when I run unit tests.
App.class
#SpringBootApplication
#Profile("!test")
public class App implements CommandLineRunner {
#Autowired
private ReportService reportService;
public static void main(String[] args) {
SpringApplication app = new SpringApplication(App.class);
app.setBannerMode(Banner.Mode.OFF);
app.run(args);
}
#Override
public void run(String... args) throws Exception {
if (args.length == 0)
reportService.generateReports();
if (args.length > 0 && args[0].equals("-p"))
for (Report report : reportService.showReports())
System.out.println(report.getId() + " : " + report.getTimestamp());
}
}
ReportServiceTest.class
#RunWith(SpringRunner.class)
#SpringBootTest(classes = App.class)
#ActiveProfiles("test")
public class ReportServiceTest {
#Autowired
private ReportRepository reportRepository;
#Autowired
private ReportService reportService;
#Test
public void testShowReports() {
List<Report> expectedReports = new ArrayList<>(3);
for(int i = 0; i< 3; i++) {
expectedReports.add(reportRepository.save(new Report()));
}
List<Report> actualReports = reportService.showReports();
assertEquals(expectedReports.size(), actualReports.size());
}
What I need to do that CommandLineRunner will be ignored when run in tests but all ApplicationContext, JPA and so on will be initialized?
UPDATE
It seems I have found the solution:
Added #Profile("!test") to App.class
Created new AppTest.class in test directory where I initialize only SpringApplication without CommandLineRunner
Added #ActiveProfile("test") to ReportServiceTest.class
AppTest.class
#SpringBootApplication
#Profile("test")
public class AppTest {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(AppTest.class);
app.setLogStartupInfo(false);
app.run(args);
}
}

JUnit failure when mocking Logger

My class to be tested is of HostApi with the static logger.
public class HostApi {
String baseUrl;
private static Logger logger=LogFactory.getLogger(HostApi.class);
/**
* Constructor
*
* #param baseUrl
* - protocol + "://" + dockerIp + ":" + dockerPort Example -
* http://192.168.99.100:2375
*/
public HostApi(String baseUrl) {
this.baseUrl = baseUrl;
}
HostRestClient client;
public Container getContainerInfo(String containerId) throws IOException, AgentException {
logger.debug("############# getContainerInfo start ###################"); //$NON-NLS-1$
String output;
String path = "/containers/" + containerId + "/json"; //$NON-NLS-1$ //$NON-NLS-2$
client = new HostRestClient();
output = client.processGetRequest(baseUrl + path);
logger.trace(output);
ObjectMapper mapper = new ObjectMapper();
Container container = mapper.readValue(output, Container.class);
logger.debug("############# getContainerInfo end ###################\n\n"); //$NON-NLS-1$
return container;
}
}
My JUnit test class is HostApiTest
#RunWith(PowerMockRunner.class)
#PrepareForTest({HostApi.class,ObjectMapper.class,LogFactory.class})
public class HostApiTest {
HostApi hp;
static Logger logger;
#BeforeClass
public static void before()
{
System.out.println("Before Class");
}
#AfterClass
public static void after() {
System.out.println("After Class");
}
#Mock
Logger loggermock;
#Before()
public void setUp() {
mockStatic(LogFactory.class);
EasyMock.expect(LogFactory.getLogger(HostApi.class)).andReturn(loggermock );
//logger=createMock(Logger.class);
// Whitebox.setInternalState(HostApi.class, logger);
hp=new HostApi("skj"); //$NON-NLS-1$
}
#Test
public void testgetContainerInfo() throws Exception{
System.out.println("abc");
HostRestClient client=PowerMock.createMock(HostRestClient.class);
ObjectMapper obj=PowerMock.createMock(ObjectMapper.class);
Container container=new Container();
container.setId("234");
String containerData=container.toString();
PowerMock.expectNew(ObjectMapper.class).andReturn(obj);
PowerMock.expectNew(HostRestClient.class).andReturn(client);
EasyMock.expect(client.processGetRequest(EasyMock.isA(String.class))).andReturn(containerData);
EasyMock.expect(obj.readValue(EasyMock.isA(String.class),EasyMock.same(Container.class))).andReturn(container);
replayAll();
assertEquals("234",hp.getContainerInfo("25").getId());
EasyMock.verify();
}
}
Without the logger in the code (i.e. commenting out in HostApi) it works, however after adding logger it throws assertion error
I added static mocking of logfactory however it does not seem to work.
What is it that I am doing wrong in mocking? I can only use powermock.
Remove ...
LogFactory.class from the #PrepareForTest({...}) annotation
#Mock Logger loggermock; from HostApiTest
mockStatic(LogFactory.class); from HostApiTest
EasyMock.expect(LogFactory.getLogger(HostApi.class)).andReturn(loggermock); from HostApiTest
Your test case has no expectations or assertions on the behaviour of the HostApi's logger so there is no need to mock it.

GWT Unit Testing with RequestFactory / Activities

I'm trying to test the start method of an Activity that uses RequestFactory.
I manage to test RF calls invoking directly the service using this article example, but I'm missing something mocking RF calls called from the tested activity.
It's more clear with the code.
EDIT : more specific
What I really want to know, is how to replace the response of a Receiver method (onSuccess,onFailure...) called in an Activity? This way I would be able to test the code inside the receiver method.
So basically here is my activity :
public class MyActivity extends AbstractActivity implements MyView.Presenter {
private List<MyEntityProxy> entities;
private MyView view;
private ClientFactory cf;
private EntityRequest entityRequest;
private AppRequestFactory rf;
#Inject
public ClientsListActivity(ClientsListViewEditor view, ClientFactory clientFactory) {
this.view = view;
this.clientFactory = clientFactory;
rf = clientFactory.getRequestFactory();
}
#Override
public void start(final AcceptsOneWidget panel, EventBus eventBus) {
view.setPresenter(this);
refreshEntities();
}
public void refreshEntities(){
entityRequest = rf.entityRequest();
entityRequest.getAll().with("opt1,"opt2").fire(new Receiver<List<MyEntityProxy>>() {
#Override
public void onSuccess(List<MyEntityProxy> response) {
entities = response;
entityRequest = requestFactory.clientRequest();
}
});
}
public List<MyEntityProxy> getEntities(){
return entities;
}
}
To test it in JUnit I use GwtMockito, so here is the test class MyActivityTest :
#RunWith(GwtMockitoTestRunner.class)
public class ClientListActivityTest{
private MyActivity activity;
private EventBus eventBus;
private AppRequestFactory rf;
#GwtMock
private ClientFactory cf;
#GwtMock
private MyView;
#GwtMock
private AcceptsOneWidget panel;
#Before
public void setUp(){
eventBus = new SimpleEventBus();
rf = RequestFactoryHelper.create(AppRequestFactory.class);
cf = new ClientFactory(eventBus,rf);
activity = new MyActivity(view,cf);
}
#Test
public void testStartActivity(){
List<EntityProxy> result = new ArrayList<EntityProxy>();
EntityProxy expectedClient = mock(EntityProxy.class);
expectedEntity.setNom("Client 1");
EntityProxy expectedClient2 = mock(EntityProxy.class);
expectedEntity.setNom("Client 2");
result.add(expectedEntity);
result.add(expectedEntity2);
//Here I have to change the requestFactory Call, so I try that but without success :
Request<?> req = mock(Request.class);
doReturn(req).when(mock(MyEntityRequest.class)).getAll();
doAnswer(RequestFactoryHelper.ok(result)).when(req).fire(any(Receiver.class));
activity.start(panel, eventBus);
assertEquals(activity.getEntities().size(),2); //This Test fails size = 0
}
}
My RequestFactoryHelper (inspired from here ) :
public class RequestFactoryHelper {
private static class MockServiceLocator implements ServiceLocator {
private final Map<Class<?>, Object> services = new HashMap<Class<?>, Object>();
#Override
public Object getInstance( Class<?> clazz ) {
// Make sure to return always the same mocked instance for each requested type
Object result = services.get( clazz );
if (result == null) {
result = mock( clazz );
services.put( clazz, result );
}
return result;
}
}
private static class MockServiceDecorator extends ServiceLayerDecorator {
#Override
public <T extends ServiceLocator> T createServiceLocator( Class<T> clazz ) {
return (T) serviceLocator;
}
}
private static MockServiceLocator serviceLocator = new MockServiceLocator();
private static ServiceLayer serviceLayer = ServiceLayer.create( new MockServiceDecorator() );
/**
* Creates a {#link RequestFactory}.
*/
public static <T extends RequestFactory> T create( Class<T> requestFactoryClass ) {
SimpleRequestProcessor processor = new SimpleRequestProcessor( serviceLayer );
T factory = RequestFactorySource.create( requestFactoryClass );
factory.initialize( new SimpleEventBus(), new InProcessRequestTransport( processor ) );
return factory;
}
/**
* Returns the same service instance as used by the RequestFactory internals.
*/
public static <T> T getService( Class<T> serviceClass ) {
T result = (T) serviceLocator.getInstance( serviceClass );
reset( result ); // reset mock to avoid side effects when used in multiple tests
return result;
}
/**
* Returns the value passed to {#link Receiver#onSuccess(Object)}
*/
public static <T> T captureResult( Receiver<T> receiver ) {
ArgumentCaptor<Object> captor = ArgumentCaptor.forClass( Object.class );
verify( receiver ).onSuccess( (T) captor.capture() );
return (T) captor.getValue();
}
public static <T> Answer<T> ok(final T result) {
return new Answer<T>() {
#Override
public T answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
Object _receiver = args[args.length - 1];
Receiver<T> receiver = (Receiver<T>)_receiver;
receiver.onSuccess(result);
return null;
}
};
}
}
This is how I tested the Receiver method "onSuccess". I created a custom Answer for Mockito.doAnswer.
The code to test.
public void myMethod(String arg1, String arg2) {
requestFactory.adminRequest().someMethod(arg1, arg2).fire(new Receiver<Void>() {
#Override
public void onSuccess(Void response) {
placeController.goTo(new MyPlace());
}
});
}
The test.
#Test
public void testMyMethod() {
String arg1 = "arg1";
String arg2 = "arg2";
when(requestFactory.adminRequest()).thenReturn(adminRequest);
when(adminRequest.someMethod(arg1, arg2)).thenReturn(request);
doAnswer(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
Receiver<Void> receiver = (Receiver<Void>) args[0];
receiver.onSuccess(null);
return null;
}
}).when(request).fire(any(Receiver.class));
myActivity.myMethod(arg1, arg2);
verify(adminRequest).someMethod(arg1, arg2);
verify(request).fire(any(Receiver.class));
verify(placeController).goTo(any(myPlace.class));
}
requestFactory, adminRequest, request and placeController are all mocks.