This question already has answers here:
How do you unittest exceptions in Dart?
(7 answers)
Closed 7 years ago.
I write some simple project in Dart (1.9.3) with unit tests using unittest library. I have a problem with checking if constructor throws an error. Here's the sample code I write for this issue purposes:
class MyAwesomeClass {
String theKey;
MyAwesomeClass();
MyAwesomeClass.fromMap(Map someMap) {
if (!someMap.containsKey('the_key')) {
throw new Exception('Invalid object format');
}
theKey = someMap['the key'];
}
}
and here are the unit tests:
test('when the object is in wrong format', () {
Map objectMap = {};
expect(new MyAwesomeClass.fromMap(objectMap), throws);
});
The problem is the test fails with following message:
Test failed: Caught Exception: Invalid object format
What do I do wrong? Is it a bug in unittest or should I test exceptions with try..catch and check if exception has been thrown?
Thanks for all!
You can test if the Exception has been thrown using:
test('when the object is in wrong format', () {
Map objectMap = {};
expect(() => new MyAwesomeClass.fromMap(objectMap), throws);
});
passing as first argument an anonymous function raising the exception.
Related
I have these sealed interface
sealed interface Result<out T> {
data class Success<T>(val data: T) : Result<T>
data class Error(val exception: Throwable? = null) : Result<Nothing>
}
when i tried to assertEquals the Success one, it pass. But when it comes to Error one, it will fail even though the content is identical. Here is simple example:
#Test
fun testSucess() = runTest {
whenever(repository.login("email", "password"))
.thenReturn(someValue)
val expected = Result.Success(data = someValue)
val actual = loginUseCase(LoginRequest("email", "password"))
verify(repository).login("email", "password")
assertEquals(expected, actual) // this will pass
}
#Test
fun testError() = runTest {
val exception = RuntimeException("HTTP Error")
whenever(repository.login("", ""))
.thenThrow(exception)
val expected = Result.Error(exception = exception)
val actual = loginUseCase(LoginRequest("", ""))
verify(repository).login("", "")
assertEquals(expected, actual) // this will fail
assertEquals(expected.toString(), actual.toString()) // this will pass
}
What is causing this and what is possible solution to this? I have read some info that it needs equals() to be overriden, but i still confused as to why it only happens in Error case only and how to properly override the equals method.
Data classes in Kotlin have an implicitly generated equals function automatically derived from all their properties.
The problem you are facing is probably due to the fact that the type of your someValue has a proper equals function, so the equals works for your Success and its property value. But Throwable does not have an equals function which means that two Throwables are only equal if they are the same instance, which is obviously not the case for expected and actual in your test assertion. I can only guess that in loginUseCase, the exception is wrapped inside another exception, or a new exception is created based on the one thrown by the repository?
Kotlin already has a built-in Result type, and I strongly recommend using that one instead of defining your own.
Nonetheless, if you use the built-in type, you will probably face the same problem, since the equals check still fails for the different exception instances.
There are several ways to solve that:
Define your own exception type and override the equals function to return true if they are both of the same type and have the same message.
Check for expected is Error (or with the default Result type that expected.isFailure), and then check that the messages are the same.
Make sure that loginUseCase throws exactly the same exception instance as is thrown by the repository.
I'm trying to write unit test for a case when an exception is thrown but somehow it is throwing null instead of exception.
The service call that I'm trying to mock.
private List<Vertex> getVertexList(final String vertexId, GraphTraversalSource graphTraversalSource, final int indexToLoop) {
return graphTraversalSource.V(vertexId).repeat(in().dedup().simplePath()).until(loops().is(indexToLoop)).toList();
}
I wrote the following to mock to throw Exception
#Mock(answer = RETURNS_DEEP_STUBS)
private GraphTraversalSource gts;
Mockito.when(gts.V(anyString()).repeat(any()).until((Predicate<Traverser<Vertex>>) any()).toList()).thenThrow(Exception.class);
Is there any way to mock this so that it throws exception? Thanks in advance.
Assuming your gts and a call to MockitoAnnotations.initMocks(this) in the #Before of the test, this style worked for me:
GraphTraversal v = mock(GraphTraversal.class);
GraphTraversal repeat = mock(GraphTraversal.class);
GraphTraversal until = mock(GraphTraversal.class);
when(gts.V(anyString())).thenReturn(v);
when(v.repeat(any())).thenReturn(repeat);
when(repeat.until((Predicate<Traverser<Vertex>>) any())).thenReturn(until);
when(until.toList()).thenThrow(RuntimeException.class);
gts.V("test-id").repeat(out()).until(__.loops().is(1)).toList();
Depending on what you are doing you might consider avoiding the mock and just throwing an exception in the traversal itself:
GraphTraversalSource g = EmptyGraph.instance().traversal();
g.inject("test-id").sideEffect(x -> {
throw new RuntimeException();
}).toList();
Obviously, that's a little different from what your mock is doing and does require the traversal to actually have data passing through it (hence my use of inject() to start the traversal rather than V() as g is bound to an EmptyGraph in this case.
This question already has answers here:
How to mock external dependencies in tests? [duplicate]
(1 answer)
How to mock specific methods but not all of them in Rust?
(2 answers)
How can I test stdin and stdout?
(1 answer)
Is there a way of detecting whether code is being called from tests in Rust?
(1 answer)
What is the proper way to use the `cfg!` macro to choose between multiple implementations?
(1 answer)
Closed 2 years ago.
I'm trying to run unit tests on a function reducer . reducer takes in a struct State and an enum Action and returns a new struct State . When the action is Action::Status , I want the function state.status_function to be called on state. I'm having trouble testing that a mock function I pass into test_status is called with state. Does anyone know what I'm getting wrong in the code below?
fn test_status() {
let mut status_mock_called: bool;
let state = State {
status_function: Box::new(|state: State| {
status_mock_called = true;
return state;
}),
};
assert_eq!(root_reducer(state, Action::Status), state);
assert!(status_mock_called);
}
Outputs the error:
`(dyn std::ops::Fn(State) -> State + 'static)` doesn't implement `std::fmt::Debug`
How can I modify a rust variable from inside a function?
Here is the state struct in case it's relevant:
#[derive(Debug, Eq, PartialEq)]
struct State {
status_function: Box<dyn Fn(State) -> State>,
}
And here is the reducer:
fn root_reducer(state: State, action: Action) -> State {
match action {
Action::Status => (state.status_function)(state),
}
}
I am using the unit testing features in Visual Studio 2013 for my application.
I am trying to write a test for a class whereby you pass in a specific object to the constructor, and depending on the state of the object passed, an exception may be thrown.
I have written stubs for each object state, and have written test cases for the scenarios where the constructor will throw an exception as follows:
TEST_METHOD(constructor_ExceptionRaised)
{
// arrange
const InvalidStub stub;
// act
auto act = [stub] { const Foo foo(stub); };
// assert
Microsoft::VisualStudio::CppUnitTestFramework::Assert::ExpectException
<MyException>(act);
}
How should I approach a scenario where I want to pass a valid stub and simply assert that no exception was raised? I want to be purely concerned with a specific MyException not being thrown (rather than any exception).
I have hacked together a test method as follows but not sure if there is a simply "1 line" approach that would fit my needs:
TEST_METHOD(constructor_NoException)
{
// arrange
const ValidStub stub;
try
{
// act
const Foo foo(stub);
}
// assert
catch (MyException e)
{
Microsoft::VisualStudio::CppUnitTestFramework::Assert::Fail();
}
catch (...)
{
Microsoft::VisualStudio::CppUnitTestFramework::Assert::Fail();
}
}
I am not confident I need to also fail "any exception" being raised, as this should(?) be picked up by the test runner (i.e. fail the test). Along the same reasoning, would the following essentially be the same test:
TEST_METHOD(constructor_NoException)
{
// arrange
const ValidStub stub;
// act
const Foo foo(stub);
// assert
// no exception
}
I used the following test method to show that a constructor doesn't throw an exception:
TEST_METHOD(constructor_NoException)
{
// arrange
const ValidStub stub;
// act
const Foo foo(stub);
// assert
Microsoft::VisualStudio::CppUnitTestFramework::Assert::IsTrue(true);
}
When an exception is raised the test automatically fails. The exception details are given in the failure message.
When no exception is raised the test will pass as I am asserting true == true.
I'm trying to mock a method that creates a local variable, tries something, and does logging if an exception is thrown. Here's a snippet of code:
public void myFunction() {
//Some stuff
try {
new File("foo").getAbsoluteFile();
} catch (SecurityException e) {
//Do some logging
}
}
I'd like to mock this logging behavior using JMockit (using version 1.8 if it matters). So I created the following test:
#Test(expected=SecurityException.class)
public void testAbsoluteFile(
#Injectable final File file
) throws IOException {
new Expectations(File.class){{
new File(anyString);
result = file;
file.getAbsoluteFile();
result = new SecurityException();
}};
myFunction();
}
The trouble is that this seems to give me a NullPointerException on the inner workings of File.getAbsoluteFile(), which I find absolutely bizarre:
java.lang.Exception: Unexpected exception, expected<java.lang.SecurityException> but was<java.lang.NullPointerException>
Caused by: java.lang.NullPointerException
at java.io.Win32FileSystem.slashify(Win32FileSystem.java:56)
at java.io.Win32FileSystem.resolve(Win32FileSystem.java:330)
at java.io.File.getAbsolutePath(File.java:556)
at java.io.File.getAbsoluteFile(File.java:572)
at com.vue.rescoreservice.ExpectationTest.myFunction(ExpectationTest.java:39)
at com.vue.rescoreservice.ExpectationTest.testAbsoluteFile(ExpectationTest.java:33)
This seems really bizarre as it's saying that a local variable in the Win32FileSystem class (an internal class not in the typical Java API) is throwing a NullPointerException, when it never did before.
The lines that are in the stack trace are as follows:
//In myFunction()
new File("foo").getAbsoluteFile();
and
//In testAbsoluteFile()
myFunction();
Why is this happening? And how can I make it so that JMockit does not throw a NullPointerException on local variables of internal classes?
That issue has been fixed in the latest jMockit version (1.14). If you don't want to migrate now, it's possible to fix the test in 1.8 (see the code below).
In this case, the #Injectable isn't necessary. The constructor of File is mocked for the Expectations and that requires the mocking of the class itself instead of a single instance. In that case, the behavior is equivalent to #Mocked (but File will be partially mocked according to the calls in the Expectations block).
The catch clause in myFunction needs to rethrow the SecurityException to allow the test to pass.
#Test(expected=SecurityException.class)
public void testAbsoluteFile() throws IOException {
new Expectations(File.class) {{
File file = new File(anyString);
file.getAbsoluteFile();
result = new SecurityException();
}};
myFunction();
}
If you prefer to declare the mock as a parameter, it will also work, but File won't be partially mocked (all the methods will be mocked).
#Test(expected=SecurityException.class)
public void testAbsoluteFile(#Mocked final File file) throws IOException {
new Expectations(){{
new File(anyString);
file.getAbsoluteFile();
result = new SecurityException();
}};
myFunction();
}
An update on #Marc-André answer.
In my case with JMockit 1.25 I had to define the file variable outside of the expectations leaving it like:
#Test(expected=SecurityException.class)
public void testAbsoluteFile() throws IOException {
File file = new File("");
new Expectations(File.class) {{
file.getAbsoluteFile();
result = new SecurityException();
}};
myFunction();
}
Maybe it was a change on JMockit prior to the answer.