Let’s start with an example. You are creating an application that allows people to ask and answer software development questions. One of the use cases is to retrieve all posts from a specific user.

You can query an endpoint to retrieve all the user posts in JSON format, but there is one catch: A post can be either a question or an answer to a question. Take a look at an example JSON from this endpoint:

Let me emphasize: Posts can be either a question or an answer. The either and or are key words. It gives you a hint that you should model your data as a Swift enum, like this:

Observe that Question and Answer have different fields, so you need an associated value in the Post enum cases. This means that you need custom parsing.

In this case, it is not hard to make Post conform to Decodable . You only need to switch the type field and call the Decodable initializer from Question or Answer .

Now you need unit tests to validate that the custom parsing works as expected. The tests will receive some input data, will produce the output model, and will validate that the model was parsed correctly.

One approach that I used before is to have the data stored in string format inside a nested struct. Take a look at this example:

But as I told you before, using JSON strings is error prone and not safe. To improve this, you can employ the JSONValue enum.

If you didn’t read my last post, I introduced a JSONValue enum to model any JSON type, one case for each possible value. You can take a peek at it below:

I also made it conform to the Decodable protocol and showed how you can use it to parse a generic JSON field. If you missed the last post and want to take a look at it, you can find a link at the bottom of this post.

JSONValue allows you to create the same kind of input data that you had in before in string format. But this time, if you make any mistake, the compiler will catch the error and the test will not build.

You can statically build the test cases with the JSONValue initializers:

It is a lot more readable now without all the character escaping. And it is type- and syntax-safe! You don’t need to worry if you add or omit JSON symbols like : and , because the swift compiler will take care of it for you.

If you like to have the data pretty printed, the Xcode code indentation shortcut can now give you a hand.

Since your tests receive JSON strings, and now you have JSONValue , you need to convert it. First, make JSONValue conform to the Encodable protocol. To do that, switch JSONValue , and for each case encode the wrapped value.

All wrapped values in JSONValue are Encodable , so you don’t have to add any code. It works out of the box.

It still does not give you a string, so you need to call JSONEncoder.encode() . It is a throwing function, which means that you’ll need to add error handling to your tests.

Here is a small extension that you can add to your unit tests target that will make the error handling much easier. Take a look:

Not a good idea to use this in production code, since it may crash your app with a fatalError . But it’s amazing for unit tests.

Passing the #file and #line to the fatalError function allows the error to be displayed in the correct place in your test.

Since the compiler is validating most of the syntax, the only time I got a fatalError was when I tried to encode a JSON Fragment . A JSON fragment is a JSON that does not have an Object or an Array as the root.

If you do need the ability to encode JSON Fragments, you can change the jsonString function to handle the fragment cases in a different way: