I'm just getting started doing some unit testing in vs2010. I have a test method that sets a private int variable and then a couple of other test methods that attempt to use that variable. The variable does correctly get set when the first test executes but when it then moves to the next test the variable is reset to 0. How can I keep the value of that variable for all tests? Here's some example code.
public MyClassFixture{
private Controller controller;
private int id;
public MyClassFixture(){
controller = new Controller();
}
[TestMethod]
public void Should_Generate_New_Id(){
id = controller.GenerateNewId();
Assert.IsTrue(id > 0);
}
[TestMethod]
public void Should_Get_New_Record(){
var record = controller.GetNewRecord(id);
Assert.IsNotNull(record);
}
}
Related
Running SonarQube Version 6.7.2 (build 37468) - LGPL v3, Junit 4 and mockito in our project, I noted that SonarQube does not recognize Mapper's unit test and decrease the project's percentual. In my local enviroment, the test works well and the coverage is 100% by Eclipse.
Below is the UT code:
#RunWith(MockitoJUnitRunner.class)
public class ClassMapperTest {
#Mock
private ClassMapper mapper;
#Mock
private ClassDTO dto;
#Before
public void setUp() {
mapper = Mockito.mock(ClassMapper.class);
dto = Mockito.mock(ClassDTO.class);
}
#Test
public void returnResource() {
Mockito.when(mapper.fromMethod(Mockito.anySet())).thenReturn(new HashSet<>());
mapper.fromMethod(new HashSet<ClassDTO>());
}
The statistics:
After Commit:
Does anyone have any idea?
Sonarqube is right with the computation. You do have a major issue within your test, the code you seem to be testing is mocked aka you are not testing the actual code, but a fake of it.
When you mock a class you create a dummy fake version of this class, which does not have any implementation (mapper = Mockito.mock(ClassMapper.class);).
you then tell your mock to return a value when a method is called Mockito.when(mapper.fromMethod(Mockito.anySet())).thenReturn(new HashSet<>());. This way you are actually not testing your fromMethod, you just testing a method, which you told in your test what to return.
A proper test would look something like this:
#RunWith(MockitoJUnitRunner.class)
public class ClassMapperTest {
private ClassMapper mapper;
#Mock
private ClassDTO dto;
#Before
public void setUp() {
mapper = new ClassMapper();
// no need to do that, MockitoJUnitRunner is doing this for you
// dto = Mockito.mock(ClassDTO.class);
}
#Test
public void returnResource() {
// calling the actual method
assertTrue(mapper.fromMethod(new HashSet<ClassDTO>()) != null);
}
}
There is also no need for the dto as it is not used within your test at all, but I left it in there, to mark the unnecessary mock instantiation, which is done by the MockitoJUnitRunner.
// Disclaimer: I am not guaranteeing that your tests will pass, with my suggestion, I only want to highlight the problem with the test.
I am using SpringBoot 1.5.9 and try to do Integration testing. Weirdly a MongoRepository.save() method updates the object when called on mock MongoRepository.
I have a Counter Class
public class Counter {
public String id;
public int seq;
public void increaseSeq() {
this.seq += 1;
}
}
And his repository
public interface CounterRepository extends MongoRepository<Counter, String>{
Counter findById(String id);
List<Counter> findAll();
}
And his service
#Service
public class CounterService {
#Autowired private CounterRepository counterRepository;
public Counter findCounter(String id) {
return counterRepository.findById(id);
}
public int getSeqAndIncrease(String id) {
Counter counter = findCounter(id);
if (counter == null) {
return -1;
}
counter.increaseSeq();
counterRepository.save(counter);
return counter.getSeq();
}
}
Now, when I do system integration and try to mock the counterRepository, it happens something that I don't expect. The counterRepository.findById() returns a Counter object where the 'seq' field is increased. Why? Does the counterRepository.save() affect the result in any way (the counterRepository is mocked, hence I suppose that save() should not have any effect)?
#RunWith(SpringRunner.class)
#SpringBootTest
public class FlowServiceTest {
#MockBean private CounterRepository counterRepository;
#Autowired private CounterService counterService;
#Before
public void setUp() {
Mockito.when(counterRepository.save(any(Counter.class))).then(arg -> arg.getArgumentAt(0, Counter.class));
Mockito.when(counterRepository.findById("flow")).thenReturn(new Counter("flow", 10));
}
#Test
public void testSavingInDatabase() {
System.out.println(counterRepository.findById("flow"));
counterService.getSeqAndIncreaseSafe("flow");
System.out.println(counterRepository.findById("flow"));
counterService.getSeqAndIncreaseSafe("flow");
System.out.println(counterRepository.findById("flow"));
}
}
It prints "10 11 12". Why doesn't it print '10 10 10'?
The problem is these lines
counterRepository.save(counter);
return counter.getSeq();
What you should be doing is this
Counter saveCounter = counterRepository.save(counter);
return savedCounter.getSeq();
In getSeqAndIncrease method, you are not returning sequence of the saved object.
By doing this you are making your mock statement for save useless. Because you are not using the value returned from mock.
tl;dr - The returned object from mock is initialized only once in mockito. So I basically got the same reference every time, and since it is a reference not a new object, the values are updated.
Complete answer: When setting
Mockito.when(counterRepository.findById("flow")).thenReturn(new Counter("flow", 10));
, it might seem intuitive to return a new object every time, but the return object is initialised only once when the test starts and will be returned at all subsequent calls.
Then, in my code I do
counter.increaseSeq();
which increases the 'seq' of found object (this object comes from Mockito). Then at the next call, Mockito returns the firstly initialised object which was updated in the meantime; Mockito does not return a new object as it might seem like.
I am working with Spring 4.3.1.RELEASE and I have the following about testing:
#RunWith(Parameterized.class)
#ContextConfiguration(classes={RootApplicationContextConfig.class})
#Transactional
public class PersonaJdbcRepositoryTest {
#ClassRule
public static final SpringClassRule SPRING_CLASS_RULE= new SpringClassRule();
#Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
#Autowired
private PersonaRepository personaJdbcRepository;
private final Persona persona;
public PersonaJdbcRepositoryTest(Persona persona){
this.persona = persona;
}
#Parameters
public static Collection<Persona[]> data() {
return Arrays.asList(new Persona[][] {
{PersonaFactory.crearPersona01()},
{PersonaFactory.crearPersona02()},
{PersonaFactory.crearPersona03()},
{PersonaFactory.crearPersona04()},
{PersonaFactory.crearPersonaMix()}
});
}
#Test
#Sql(scripts={"classpath:/com/manuel/jordan/h2/h2-elimination-script.sql"})
public void saveOneTest(){
Persona personaSaveOne = personaJdbcRepository.saveOne(persona);
Persona personaFindOne = personaJdbcRepository.findOne(personaSaveOne.getId());
assertEquals(personaFindOne, personaSaveOne);
}
#Test
public void findOneTest(){
Persona personaFindOne = personaJdbcRepository.findOne(persona.getId());
assertEquals(personaFindOne, persona);
}
#Test
public void findAllTest(){
Collection<Persona> personas = PersonaFactory.crearPersonas();
Collection<Persona> personasFindAll = personaJdbcRepository.findAll();
assertEquals(personas.size(), personasFindAll.size());
}
}
I can confirm that each #Test is executed and pass N times (in this case 5) according with data().
My requirement is that: I only need one execution of the findAllTest() method. I mean, it is executed 4 times unnecessarily. Even more when it does not use the persona object.
Therefore is possible indicate through SpringClassRule/SpringMethodRule that a #Test method just works once? How?
Is it possible to indicate through SpringClassRule/SpringMethodRule that a #Test method just runs once?
No. That is not possible.
The behavior you are experiencing has nothing to do with Spring.
It is the Parameterized runner that controls how many times a test method is executed.
If you don't want a test method to be parameterized, simply move it to a different test class that does not use the Parameterized runner.
I'm getting into writing unit testing and have implemented a nice repository pattern/moq to allow me to test my functions without using "real" data. So far so good.. However..
In my repository interface for "Posts" IPostRepository I have a function:
Post getPostByID(int id);
I want to be able to test this from my Test class but cannot work out how.
So far I am using this pattern for my tests:
[SetUp]
public void Setup()
{
mock = new Mock<IPostRepository>();
}
[Test]
public void someTest()
{
populate(10); //This populates the mock with 10 fake entries
//do test here
}
In my function "someTest" I want to be able to call/test the function GetPostById. I can find the function with mock.object.getpostbyid but the "object" is null.
Any help would be appreciated :)
iPostRepository:
public interface IPostRepository
{
IQueryable<Post> Posts {get;}
void SavePost(Post post);
Post getPostByID(int id);
}
I'm not sure what unit testing framework you are using, but I am using NUnit. I'm not a unit testing pro, but I know enough to get me started and to get results.
I normally have a service layer, and this will call my post repository:
public class PostService
{
private readonly IPostRepository postRepository;
public PostService(IPostRepository postRepository)
{
if (postRepository== null)
{
throw new ArgumentNullException("postRepository cannot be null.", "postRepository");
}
this.postRepository = postRepository;
}
public Post GetPostById(int id)
{
return postRepository.GetPostById(id);
}
}
Your unit tests could look like this:
[TestFixture]
public class PostServiceTests
{
private PostService sut;
private Mock<IPostRepository> postRepositoryMock;
private Post post;
[SetUp]
public void Setup()
{
postRepositoryMock = new Mock<IPostRepository>();
sut = new PostService(postRepositoryMock.Object);
post = new Post
{
Id = 5
};
}
[Test]
public void GetPostById_should_call_repository_to_get_a_post_by_id()
{
int id = 5;
postRepositoryMock
.Setup(x => x.GetPostById(id))
.Returns(post).Verifiable();
// Act
Post result = sut.GetPostById(id);
// Assert
Assert.AreEqual(post, result);
postRepositoryMock.Verify();
}
}
I hope this helps.
If you want your mock object to return a result (not null), you need to set it up:
mock.Setup( m => m.GetPostByID( 5 ) ).Returns( new Post() );
What you return exactly is up to you of course.
Update:
If you need to use the method parameters you can also setup a CallBack. For example:
mock.Setup( m => m.GetPostByID( It.IsAny<int>() ) )
.Callback( id => return new Post{ Id = id; } );
This may make your setup code much easier since you don't need to prime the mock with data.
If you want to test the real implementation of GetPostById, do so via the real implementation of IPostRepository. Moq (and mocks in general) are only for situation where you don't want to use the real thing.
In other words prime your database with some posts, new up the real repository, call GetPostById and make assertions on the result. This is not strictly a unit test though, but an integration test because it includes the database.
I have two [TestMethods]. The result of MethodA needs to be the input of MethodB. The problem is that all values and variables are reset when a new test method starts.
Somebody has already asked the exact same question, but there was no real solution yet.
All I want is the following to work:
Guid CustomerID;
[TestMethod]
public void CreateCustomer()
{
// Create a new customer and store the customer id
CustomerID = CreateNewCustomer();
Assert.IsNotNull(...);
}
[TestMethod]
public void DeleteCustomer()
{
// Delete the customer created before
var ok = DeleteCustomer(CustomerID);
Assert.IsNotNull(...);
}
I understand that this is not the "official" way for testing, but I really need a practical solution for this scenario -so I am hoping for some kind of workaround.
Any ideas?
Why not create the customer in your delete customer test?
[TestMethod]
public void CreateCustomer()
{
// Create a new customer and store the customer id
var customerID = CreateNewCustomer();
Assert.IsNotNull(...);
}
[TestMethod]
public void DeleteCustomer()
{
// Delete the customer created before
var customerID = CreateNewCustomer();
var ok = DeleteCustomer(customerID);
Assert.IsNotNull(...);
}
or just create the customer in the testfixture set up:
(The name of the TestFixtureSetUp might be different in VS test environment, that is what it is called in NUnit, but there will be an equivalent)
private Guid CustomerID;
[TestFixtureSetUp]
{
**EDIT** you could ensure you DB is clean here:
CleanDB();
CustomerID = CreateNewCustomer();
}
[TestMethod]
public void CreateCustomer()
{
// check previously created customer
Assert.IsNotNull(...);
}
[TestMethod]
public void DeleteCustomer()
{
// Delete the customer created before
var ok = DeleteCustomer(CustomerID);
Assert.IsNotNull(...);
}
[TestFixtureTearDown]
{
**EDIT** or you could ensure you DB is clean here:
CleanDB();
}
The first solution is better in my opinion as each test is responsible for creating its own data, but if this is an integration test which is actually putting stuff into and out of the database then it is ok (again in my opinion) to have the data needed for all tests to be done in the setup for that class and then all tests can run expecting the data to be there. You should ensure though that each test class also has a corresponding test tear down which will remove this classes test data from the db, or that you are cleaning the DB somewhere before each test class is run (like in a common base class)
You need to use [TestInitialize] method for test prerequisities as in your case for creating new customer because each [TestMethod] is ran standalone.