Search code examples
iosarraysswiftunit-testingcore-data

Swift Fatal error: … Expected <some type> but found <some type>


My app uses CoreData. One of the entities is

final class ViewItem: NSManagedObject {
// …
}  

During unit tests, I am trying to execute the following fetch request:

let viewItemFetchRequest = NSFetchRequest<ViewItem>(entityName: "ViewItem")  

as

viewContext.performAndWait {
  do {
    let fetchedViewItems = try viewContext.fetch(viewItemsFetchRequest)
    let viewItems = Set(fetchedViewItems)
    // …
  }  

Although the code executes correctly during normal operation, during unit tests it crashes.

When I set a breakpoint behind the try instruction, this breakpoint is reached, i.e. the fetch does not throw.
However I get a fatal error when I want to access fetchedViewItems, either by Set(fetchedViewItems) or with

(lldb) po fetchedViewItems
Fatal error: NSArray element failed to match the Swift Array Element type
Expected ViewItem but found ViewItem
2022-06-07 10:31:30.245019+0200 ShopEasy[42069:1864673] Fatal error: NSArray element failed to match the Swift Array Element type
Expected ViewItem but found ViewItem
1 value  

Here is the relevant part of the stack frame:
enter image description here

What could be the reason and how could I fix the problem?

PS: I found some posts related to this error, this, this and this one, but in none of them is reported Expected <some type> but found <some type>.

EDIT:

To investigate the situation, I modified the code as follows:

viewContext.performAndWait {
  do {
    let fetchedViewItems: [ViewItem] = try viewContext.fetch(viewItemsFetchRequest)
    let fetchedObjects: [AnyObject] = try viewContext.fetch(viewItemsFetchRequest)
    let viewItems = Set(fetchedViewItems)
    // …
  }  

and set a breakpoint at let viewItems = Set(fetchedViewItems), the instruction that crashes.
This is the situation when the breakpoint is reached:

Printing the description of fetchedObjects in the Variables View of the Debug area gives

Printing description of fetchedObjects:
▿ 1 element
  ▿ 0 : <ShopEasy.ViewItem: 0x10b3147c0> (entity: ViewItem; id: 0x10b822540 <x-coredata:///ViewItem/t51E2E772-5F7C-43E4-BBC6-68DC139F1BE02>; data: {
    fixedAtTopAt = nil;
…

and in the console

(lldb) po fetchedObjects
▿ 1 element
  ▿ 0 : <ShopEasy.ViewItem: 0x10b3147c0> (entity: ViewItem; id: 0x10b822540 <x-coredata:///ViewItem/t51E2E772-5F7C-43E4-BBC6-68DC139F1BE02>; data: {
    fixedAtTopAt = nil;
…

However, printing the description of fetchedViewItems in the Variables View of the Debug area gives

Printing description of fetchedViewItems:
([ShopEasyTests.ViewItem]) fetchedViewItems = 1 value {
  [0] = 0x000000010b3147c0
}

but in the console

(lldb) po fetchedViewItems
Fatal error: NSArray element failed to match the Swift Array Element type
Expected ViewItem but found ViewItem
2022-06-08 08:54:02.359228+0200 ShopEasy[51124:2241262] Fatal error: NSArray element failed to match the Swift Array Element type
Expected ViewItem but found ViewItem
1 value

This seems to be some conflict between the apps namespace (ShopEasy.ViewItem) and the unit tests namespace (ShopEasyTests.ViewItem).


Solution

  • I could reproduce your error in a sample project where the managed object class definition file was added both to the application target and the unit tests target. This also gave some console warnings when running tests about the class being implemented in two places.

    Is this what is happening in your case?

    enter image description here

    The code should only be present in your app target, and you should use @testable import ShopEasy to access app code in your unit tests.