The scenario is I am trying to validate a domain object and store the validation messages in another object. The class is Validator and the method looks like:
public void validate (Domain domain, ValidationInfo info)
And the ValidationInfo object has:
List<String> messages = new ArrayList<String> messages ()
The Validator class is called from a service class. Whatever validation fails for the domain object the failure messages will be stored in the list in the ValidationInfo class.
In the service test class in one of the test case i wrote the following to test the validation failure:
#Test
public void testvalidation () throws Exception {
Domain domain = createDomainWithInvalidData();
service.create (domain);
verify(mockValidator).validate(domain, validationInfo);
assertFalse (validationInfo.getMessages().isEmpty());
Now What I want is to get the failure messages from the validationInfo object so that I can write some asserts based on that. But it's not working.
Can anybody shed some light on this.
From what I gather you are unit testing the service.
Actually there's is no point in getting the messages from validationInfo as it is passed to a method of Mockito mock which does nothing by definition unless you write a stub (given(...).willReturn(...)). Even the last assertion in your code sample is not necessary as validationInfo won't be modified by the default mocked behavior of validate.
Mockito is designed and lead to test interactions between collaborators, which is already done with your verification verify(...), as you are testing the service and his collaboration with the Validator.
Testing the message that was written in ValidationInfo has nothing to do with the scope of service
However what you want is to unit test the Validator, in which you should write specific tests for validation messages. Look at the following snippet where I imaginated some part of the ValidationInfo API :
public class ValidatorTest {
Validator validator = new Validator(); // not a mock
#Test
public void when_<some_part_of_the_domain>_is_incorrect_report_validation_error() throws Exception {
// given
Domain domain = createDomainWithInvalidData();
// when
validator.validate(domain, validationInfo);
// then
assertThat(validationInfo.getMessages()).isNotEmpty()); // not really necessary
assertThat(validationInfo.getLastMessage().text()).contains("<some_part_of_the_domain> is wrong");
}
}
Note that I used the BDD keywords (given, when, then) to help me write the test. Alos I used FestAssert library which affer great assertion tools.
Hoep that helps.
I was able to achieve what i wanted after breaking my head for hours.
What we need to do is use doAnswer of mockito. Please find below the snippet:
doAnswer(new Answer<ValidationInfo> () {
#Override
public ValidationInfo answer (InvocationOnMock invocationOnMock) throws Throwable {
Object [] args = invocationOnMock.getArguments();
ValidationInfo vi = (ValidationInfo) args [1];
vi.getMessages.add("some message");
return vi;
}}).when(validator).validate (domain, validationInfo);
This way I was able to put custom failure messages in the list which made the validation fail in the service; which was the whole purpose of the test.
And earlier the test was not passing because in the service code there was a check on the size of the list. And the list size was always zero as verify will just verify whether the method gets called or not but wont actually change the state of the object.
Hope this helps. If there is any better way of achieving this please comment.
Related
I have written to Unit test - junit with Mockito library to test any methods, who save to databases new account - addNewAccount methods.
I would like to ask - if I need to add a method or what and how - to delete/remove an account, whos was added. and please show me what I can do it.
my unit test is:
#Test
public void shouldSaveaAccountToDb() {
Account acc = new Account();
acc.setUser(this.user);
acc.setEmail(this.mail);
String account = this.accountController.addNewAccount(this.user, this.mail);
verify(this.accountRepepetytory)).save(Mockito.refEq(acc, new String[0]));
Assert.assertThat(account, CoreMatchers.is("Account"));
}
I also want to add a case with a null value and testing null and empty string. if you can any idea to add test case please tell me.
thank you very match for help. I improved my test.
I have also a method who testing with null value. This is the method.
#Test
public void SaveToDatabaseWithNull() {
Account acc = new Account();
String mail = null;
user.setMail((String)mail);
user.setUser(this.user);
String account = this.accountController.addNewAccount(this.user, (String)mail);
verify(this.accountRepetytory)).save(Mockito.refEq(uaccount, new String[0]));
Assert.assertThataccountCoreMatchers.is("Account"));
}
I also would like to ask, whether in these tests it is necessary to delete some values, adding a method that deletes the account. if I create an account in one method, do I have to delete it in some way and in which way? to test correctly with the null value in the later method.
In your code you have some weaknesses that make you test britle and hard to understand:
Each test method should verify one single expectation only.
Your test verifies two things:
The code created an object of class Account that equals to the one created in the test method by the means of the Account classes implementation of equals().
The return value of the method is a string with content "Account".
Problem of that is that the test does not explain why you expect that string.
So basically you should have separate methods to verify either behavior allowing for a better description of the tested behavior in the test method name.
reduce dependencies to unrelated code.
Mockito.refEq() relies on a (correct) implementation of the equals method in class Account. There is no quaratee that this method is actually implemented or (even worse) may need addioional configuration in future if an account gets more properties that are not allowed to be null.
The better way here is to use an ArgumentCaptor and verify the properties of the captures object:
#Test
public void shouldPassAnAccountObjectWithNameAndEmailSetToDB() {
ArgumentCaptor<Account> accountCaptor =
ArgumentCaptor.forClass(
Account.class);
this.accountController.addNewAccount(
this.user,
this.mail);
verify(this.accountRepepetytory))
.save(
accountCaptor.capture());
Assert.assertThat(
"user",
accountCaptor.getValue().getUser(),
CoreMatchers.is(this.user));
Assert.assertThat(
"email",
accountCaptor.getValue().getEmail(),
CoreMatchers.is(this.email));
}
Consider the scenario where I am mocking certain service and its method.
Employee emp = mock(Employee.class);
when(emp.getName(1)).thenReturn("Jim");
when(emp.getName(2)).thenReturn("Mark");
//assert
assertEquals("Jim", emp.getName(1));
assertEquals("Mark", emp.getName(2));
In the above code when emp.getName(1) is called then mock will return Jim and when emp.getName(2) is called mock will return Mark. My Question is I am declaring the behavior of Mock and checking it assertEquals what is the point in having above(or same kind of) assert statements? These are obviously going to pass. it is simply like checking 3==(1+2) what is the point? When will these tests fail (apart from changing the return type and param type)?
As you noted, these kind of tests are pointless (unless you're writing a unit test for Mockito itself, of course :-)).
The point of mocking is to eliminate external dependencies so you can unit-test your code without depending on other classes' code. For example, let's assume you have a class that uses the Employee class you described:
public class EmployeeExaminer {
public boolean isJim(Employee e, int i) {
return "Jim".equals(e.getName(i));
}
}
And you'd like to write a unit test for it. Of course, you could use the actual Employee class, but then your test won't be a unit-test any more - it would depend on Employee's implementation. Here's where mocking comes in handy - it allows you to replace Employee with a predictable behavior so you could write a stable unit test:
// The object under test
EmployeeExaminer ee = new EmployeeExaminer();
// A mock Employee used for tests:
Employee emp = mock(Employee.class);
when(emp.getName(1)).thenReturn("Jim");
when(emp.getName(2)).thenReturn("Mark");
// Assert EmployeeExaminer's behavior:
assertTrue(ee.isJim(emp, 1));
assertFalse(ee.isJim(emp, 2));
In your case you are testing a getter, I don't know why you are testing it and no clue why would you need to mock it. From the code you are providing this is useless.
There is many scenarios where mocking make sense when you write unit-test you have to be pragmatic, you should test behaviors and mock dependencies.
Here you aren't testing behavior and you are mocking the class under test.
There is no point in that test.
Mocks are only useful for injecting dependencies into classes and testing that a particular behaviour interacts with that dependency correctly, or for allowing you to test some behaviour that requires an interface you don't care about in the test you are writing.
Mocking the class under test means you aren't even really testing that class.
If the emp variable was being injected into another class and then that class was being tested, then I could see some kind of point to it.
Above testcase is trying to test a POJO.
Actually, You can ignore to test POJO's, or in other words, they are automatically tested when testing other basic functionalities. (there are also utilities as mean-beans to test POJO's)
Goal of unit-testing is to test the functionality without connecting to any external systems. If you are connecting to any external system, that is considered integration testing.
Mocking an object helps in creating mock objects that cannot be created during unit-testing, and testing behavior/logic based on what the mocked object (or real object when connecting to external system) data is returned.
Mocks are structures that simulate behaviour of external dependencies that you don't/can't have or which can't operate properly in the context of your test, because they depend on other external systems themselves (e.g. a connection to a server). Therefore a test like you've described is indeed not very helpful, because you basically try to verify the simulated behaviour of your mocks and nothing else.
A better example would be a class EmployeeValidator that depends on another system EmployeeService, which sends a request to an external server. The server might not be available in the current context of your test, so you need to mock the service that makes the request and simulate the behaviour of that.
class EmployeeValidator {
private final EmployeeService service;
public EmployeeValidator(EmployeeService service) {
this.service = service;
}
public List<Employee> employeesWithMaxSalary(int maxSalary) {
List<Employee> allEmployees = service.getAll(); // Possible call to external system via HTTP or so.
List<Employee> filtered = new LinkedList<>();
for(Employee e : allEmployees) {
if(e.getSalary() <= maxSalary) {
filtered.add(e);
}
}
return filtered;
}
}
Then you can write a test which mocks the EmployeeService and simulates the call to the external system. Afterwards, you can verify that everything went as planned.
#Test
public void shouldContainAllEmployeesWithSalaryFiveThousand() {
// Given - Define behaviour
EmployeeService mockService = mock(EmployeeService.class);
when(mockService.getAll()).thenReturn(createEmployeeList());
// When - Operate the system under test
// Inject the mock
EmployeeValidator ev = new EmployeeValidator(mockService);
// System calls EmployeeService#getAll() internally but this is mocked away here
List<Employee> filtered = ev.employeesWithMaxSalary(5000);
// Then - Check correct results
assertThat(filtered.size(), is(3)); // There are only 3 employees with Salary <= 5000
verify(mockService, times(1)).getAll(); // The service method was called exactly one time.
}
private List<Employee> createEmployeeList() {
// Create some dummy Employees
}
I'm creating a database wrapper. This wrapper has a series of states:
it is created
you are signing in
you are signed id
you are connected to a specific table
Methods on my database wrapper can trigger the state transitions.
But the database interactions are asynchronous, so you don't get immediate feedback. Instead, you can register as a listener for onStateChanged events.
I'm using mockito to test the transitions, and so far I'm really amazed at how clean the use of InOrder and verify are.
But now I'm running into a problem. I'm trying to test a forbidden transition. My Database wrapper will catch that you're not in the correct state and throw an AssertionException. This Exception let's the testing crash. I'm trying to register this as an expected exception with Mockito, but I can't figure out how to do this in the correct way.
The following code is all in one function, the exception is expected by JUnit:
#Test(expected = AssertionError.class)
public void cantCreateTwice() throws Exception{
...
First I'm creating a connection, and I'm setting up a StateChangeListener which attempts the forbidden transition:
final FirebaseConnection connection = new FirebaseConnection();
StateChangeListener stateChangeListener = new StateChangeListener() {
#Override
public void onStateChanged(DBState newState) {
if(newState==DBState.SignedIn){
connection.createParty();
connection.createParty(); // forbidden
}
}
};
Next, I'm registering this listener and a mock:
StateChangeListener mockedListener = mock(StateChangeListener.class);
connection.addStateChangeListener(stateChangeListener);
connection.addStateChangeListener(mockedListener);
Then I tell Mockito about the expected exception and start the test:
doThrow(new AssertionError()).when(mockedListener).onStateChanged(DBState.SignedIn);
connection.signIn();
verify(mockedListener, times(1)).onStateChanged(DBState.SigninIn);
verify(mockedListener, times(1)).onStateChanged(DBState.SignedIn);
This will result in:
Test running failed: Instrumentation run failed due to 'Process
crashed.'
The exception that crashed the process is the expected AssertionError:
java.lang.AssertionError: the connection is not in the necessary state
I think the problem is that my exception is not triggered when a function is called on the mocked listener, but on the anonymous implementation.
But I need the anonymous implementation to trigger the forbidden functionality.
I also need the verify since my callbacks are asynchronous. If I remove the verify then the test will simply return immediately without any exception being thrown.
It seems to me that I somehow need to convert my anonymous implementation into a Mock object that can be supervised by Mockito. But mock() doesn't work on anonymous classes. And I think it's not correct to have an individual class for every snippet of logic in my test cases.
How can I tell Mockito to expect this exception ?
EDIT:
I think I've found a way, I'm using verify with a timeout:
verify(mockedListener, timeout(1000).times(1)).onStateChanged(DBState.SigninIn);
verify(mockedListener, timeout(1000).times(1)).onStateChanged(DBState.SignedIn);
connection.createParty();
connection.createParty();
This blocks until the sign-in was completed. Then it tries to create a party twice, which fails and throws the expected exception.
But I think I'm now basically misusing a feature of Mockito for synchronization. Is this the correct way to use Mockito for my problem ?
I am testing mail functionality in my code with the UnitilsJUnit4 and EasyMock.
My code is like this..
public void prepare(MimeMessage mimeMessage) {
// some code ..
MimeMessageHelper message = new MimeMessageHelper( mimeMessage, true );
// some mail settings ..
}
when I am testing the method prepare, it is giving the below exception.. but the method it is showing below is from the Spring framework class.
java.lang.AssertionError:
Unexpected method call setContent(javax.mail.internet.MimeMultipart#6e616e61):
setContent(javax.mail.internet.MimeMultipart#2dda2dda): expected: 1, actual: 0
at $javax.mail.internet.MimeMessage$$EnhancerByCGLIB$$614de43f.setContent(<generated>)
at org.springframework.mail.javamail.MimeMessageHelper.createMimeMultiparts(MimeMessageHelper.java:344)
at org.springframework.mail.javamail.MimeMessageHelper.<init>(MimeMessageHelper.java:290)
at org.springframework.mail.javamail.MimeMessageHelper.<init>(MimeMessageHelper.java:247)
at org.springframework.mail.javamail.MimeMessageHelper.<init>(MimeMessageHelper.java:226)
Please help me to resolve the above issue.. how to test my method?
I know this was written a long time ago, but I just encountered this exact same problem.
If you can mock the MimeMessageHelper in some form you can easily test the code. I did this by creating an interface that simply supplies back the MimeMessageHelper class and adding that as a dependency to the class I was testing.
Interface:
public interface MimeMessageHelperProvider {
MimeMessageHelper getMimeMessageHelper(MimeMessage mimeMessage);
}
Implementation:
public class MimeMessageHelperProviderImpl implements MimeMessageHelperProvider {
#Override
public MimeMessageHelper getMimeMessageHelper(MimeMessage mimeMessage) {
return new MimeMessageHelper(mimeMessage);
}
}
Now you can wire in the MimeMessageHelperProvider and simply mock that interface to have it return you an instance you can verify against.
You seem to be mocking the wrong thing. You're mocking the Mail API when you should be mocking the Spring class, since that's what you interact with directly. The way you're doing it now, you're effectively testing the Spring class along with your own, which isn't really what you want.
You need to mock the MimeMessageHelper. You can't inject it because it takes mimeMessage in the constructor. So to do this you need something like PowerMock.
From the documentation:
Use the #RunWith(PowerMockRunner.class) annotation at the
class-level of the test case.
Use the #PrepareForTest(ClassThatCreatesTheNewInstance.class)
annotation at
the class-level of the test case.
Use
PowerMock.createMock(NewInstanceClass.class) to create a mock
object
of the class that should be constructed (let's call it
mockObject).
Use
PowerMock.expectNew(NewInstanceClass.class).andReturn(mockObject)
to
expect a new construction of an object of type
NewInstanceClass.class but instead return the mock object.
Use
PowerMock.replay(mockObject, NewInstanceClass.class) to change the
mock object and class to replay mode, alternatively use the
PowerMock.replayAll() method.
Use PowerMock.verify(mockObject,
NewInstanceClass.class) to change the mock object and class to
verify mode, alternatively use the PowerMock.verifyAll() method.
Obviously, I don't really know what you're trying to test, but your test would look something like:
#RunWith(PowerMockRunner.class)
#PrepareForTest(MessagePreparer.class)
public class MessagePreparerTest {
#Test
public void testPrepare() {
MimeMessage mockMessage = PowerMock.createMock(MimeMessage.class);
MimeMessageHelper mockMessageHelper = PowerMock.createMock(MimeMessageHelper.class);
PowerMock.expectNew(MimeMessageHelper.class,
mockMessage, true).andReturn(mockMessageHelper);
// ...set other expectations
PowerMock.replay(mockMessage, mockMessageHelper, MimeMessageHelper.class);
MessagePreparer messagePreparer = new MessagePreparer();
messagePreparer.prepare(mockMessage);
PowerMock.verify(mockMessage, mockMessageHelper, MimeMessageHelper.class);
}
}
Let's say I'm writing an application and I need to be able to do something like this:
String url = "https://someurl/";
GetMethod method = new GetMethod(URLEncoder.encode(url));
String content = method.getResponseBodyAsString();
Is there a way to provide a mock server that would let me handle the https request? What I'm looking for is a way to write unit tests, but I need to be able to mock the part that actually goes out to https://someurl so I can get a known response back.
Take a look at jadler (http://jadler.net), an http stubbing/mocking library I've been working on for some time. The 1.0.0 stable version has been just released, it should provide the capabilities you requested:
#Test
public void getAccount() {
onRequest()
.havingMethodEqualTo("GET")
.havingURIEqualTo("/accounts/1")
.havingBody(isEmptyOrNullString())
.havingHeaderEqualTo("Accept", "application/json")
.respond()
.withTimeout(2, SECONDS)
.withStatus(200)
.withBody("{\"account\":{\"id\" : 1}}")
.withEncoding(Charset.forName("UTF-8"))
.withContentType("application/json; charset=UTF-8");
final AccountService service = new AccountServiceRestImpl("http", "localhost", port());
final Account account = service.getAccount(1);
assertThat(account, is(notNullValue()));
assertThat(account.getId(), is(1));
}
#Test
public void deleteAccount() {
onRequest()
.havingMethodEqualTo("DELETE")
.havingPathEqualTo("/accounts/1")
.respond()
.withStatus(204);
final AccountService service = new AccountServiceRestImpl("http", "localhost", port());
service.deleteAccount(1);
verifyThatRequest()
.havingMethodEqualTo("DELETE")
.havingPathEqualTo("/accounts/1")
.receivedOnce();
}
You essentially have two options:
1. Abstract the call to the framework and test this.
E.g. refactor the code to allow you to inject a mock implementation at some point. There are many ways to do this. e.g. create a getUrlAsString() and mock that. (also suggested above). Or create a url getter factory that returns a GetMethod object. The factory then can be mocked.
2. Start up a app server as part of the test and then run your method against it. (This will be more of an integration test)
This can be achieved in an number of ways. This can be external to the test e.g. the maven jetty plugin. or the test can programmatically start up the server. see: http://docs.codehaus.org/display/JETTY/Embedding+Jetty
Running it over https will complicate this but it will still be possible with self signed certs. But I'd ask yourself - what exactly you want to test? I doubt you actually need to test https functionality, its a proven technology.
Personally I'd go for option 1 - you are attempting to test functionality of an external library. That is usually unnecessary. Also it's good practice to abstract out your dependencies to external libraries.
Hope this helps.
If you are writing a unit test, you dont want any external dependencies. from the api,
GetMethod
extends
HttpMethod
so you can easily mock it with your favorite mocking library. Your
method.getResponseBodyAsString()
call can be mocked to return any data you want.
You can wrap that code in some class and have WebClient.getUrl() and then mock (e.g. jmock) that method to return stored files - say
expectation {
oneOf("https://someurl/"), will(returnValue(someHTML));
}
Take a look at JWebUnit http://jwebunit.sourceforge.net/
Here is an example of a test...Its really quite intuitive.
public class ExampleWebTestCase extends WebTestCase {
public void setUp() {
super.setUp();
setBaseUrl("http://localhost:8080/test");
}
public void test1() {
beginAt("/home");
clickLink("login");
assertTitleEquals("Login");
setTextField("username", "test");
setTextField("password", "test123");
submit();
assertTitleEquals("Welcome, test!");
}
}
You could always launch a thttpd server as part of your unit test to serve the requests locally. Though, ideally, you have a well tested GetMethod, and then you can just mock it, and not have to actually have a remote server around for ALL of your tests.
Resources
thttpd: http://www.acme.com/software/thttpd/
To what extend are you interested in mocking this "Get" call, because if you are looking for a general purpose mocking framework for Java which integrates well with JUnit and allows to setup expectations which are automatically asserted when incorporated into a JUnit suite, then you really ought to take a look at jMock.
Now without more code, it's hard to determine whether this is actually what you are looking for, but a (somewhat useless) example, of something similar to the example code you wrote, would go something like this:
class GetMethodTest {
#Rule public JUnitRuleMockery context = new JunitRuleMockery();
#Test
public void testGetMethod() throws Exception {
// Setup mocked object with expectations
final GetMethod method = context.mock(GetMethod.class);
context.checking(new Expectations() {{
oneOf (method).getResponseBodyAsString();
will(returnValue("Response text goes here"));
}});
// Now do the checking against mocked object
String content = method.getResponseBodyAsString();
}
}
Use xml mimic stub server, that can simulate static http response based on request parameters, headers, etc. It is very simple to configure and use it.
http://xmlmimic.sourceforge.net/
http://sourceforge.net/projects/xmlmimic/