首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >使用对象化实体模型进行模拟测试时的关键问题(&K)

使用对象化实体模型进行模拟测试时的关键问题(&K)
EN

Stack Overflow用户
提问于 2015-02-17 17:57:39
回答 2查看 974关注 0票数 3

我不确定我是否应该全力以赴而不是这样做,但我通常习惯于模拟我的应用程序的许多区域,当我在实体中使用Ref和Keys时会遇到问题。

我遵循了docs中的模式,在实体中使用引用,但您屏蔽了引用,以便可以访问它引用的驱动程序对象,如下所示:

代码语言:javascript
复制
@Entity
class Car {
    @Id Long id;
    @Load Ref<Person> driver;    // Person is an @Entity

    public Person getDriver() { return driver.get(); }
    public void setDriver(Person value) { driver = Ref.create(value); }
}

我的特定场景是使用一个导入器,在那里我正在解析xml并构建准备保存它们的实体。因为我的单元测试实际上只是测试xml的导入和解析,所以我模拟了我的dao实现,所以我实际上并没有使用数据存储。

然后我遇到了问题,当我调用setDriver时,它只是创建了一个引用对象。然后,我使用getDriver方法,该方法将返回null,因为Ref.get直接依赖于数据存储。

有没有人遇到过这个问题,有没有办法创建一个模拟引用对象?我正在考虑在我的实体中不直接引用Ref,而是引用一个可以提供我在测试中控制的Ref的帮助器类?

EN

回答 2

Stack Overflow用户

发布于 2015-06-03 15:48:01

我将Ref包装在一个Guava供应商中,以避免在pojos的单元测试期间对Objectify的依赖。以与Ref类似的方式将供应商转换为数据存储关键字。

此类主要从Objectify RefTranslatorFactory复制而来

代码语言:javascript
复制
public class RefSupplierTranslatorFactory
    extends ValueTranslatorFactory<Supplier<?>, com.google.appengine.api.datastore.Key> {
@SuppressWarnings({ "unchecked", "rawtypes" })
public RefSupplierTranslatorFactory() {
    super((Class) Supplier.class);
}

@Override
protected ValueTranslator<Supplier<?>, com.google.appengine.api.datastore.Key> createValueTranslator(
        TypeKey<Supplier<?>> tk, CreateContext ctx, Path path) {

    final LoadConditions loadConditions = new LoadConditions(tk.getAnnotation(Load.class));

    return new ValueTranslator<Supplier<?>, com.google.appengine.api.datastore.Key>(
            com.google.appengine.api.datastore.Key.class) {

        @Override
        protected Supplier<?> loadValue(com.google.appengine.api.datastore.Key value, LoadContext ctx, Path path)
                throws SkipException {
            Ref<Object> ref = ctx.loadRef(Key.create(value), loadConditions);
            return new RefSupplier(ref);
        }

        @Override
        protected com.google.appengine.api.datastore.Key saveValue(Supplier<?> value, boolean index,
                SaveContext ctx, Path path) throws SkipException {
            return ctx.saveRef(Ref.create(value.get()), loadConditions);
        }
    };
}

public static class RefSupplier
        implements Serializable, Supplier<Object> {
    private static final long serialVersionUID = 1L;
    final private Ref<?> ref;

    public RefSupplier(Ref<?> ref) {
        this.ref = ref;
    }

    @Override
    public Object get() {
        return ref.get();
    }

}
}

假设我有以下Pojos:

代码语言:javascript
复制
@Entity
public static class CarWithSupplier {
    @Id
    Long id;
    Supplier<SteeringWheel> steeringWheel;
    List<Supplier<Tire>> tires;
}

@Entity
public static class SteeringWheel {
    @Id
    Long id;
}

@Entity
public static class Tire {
    @Id
    Long id;
}

我可以在不依赖Objectify的情况下运行单元测试:

代码语言:javascript
复制
@Test
public void testSupplier() {
    CarWithSupplier car = carWithSupplier();
    assertNotNull(car.steeringWheel);
    assertNotNull(car.tires);
    assertEquals(2, car.tires.size());
}

protected CarWithSupplier carWithSupplier() {
    CarWithSupplier car = new CarWithSupplier();
    car.steeringWheel = Suppliers.ofInstance(steeringWheel());
    final Supplier<Tire> leftFrontTire = Suppliers.ofInstance(tire());
    final Supplier<Tire> rightFrontTire = Suppliers.ofInstance(tire());
    car.tires = ImmutableList.of(leftFrontTire, rightFrontTire);
    return car;
}

扩展单元测试,但在测试设置期间设置必要的对象化资源,我能够获得对数据存储运行相同的单元测试:

代码语言:javascript
复制
@Before
public void setUpObjectify() throws Exception {
    helper.setUp();
    closeable = ObjectifyService.begin();
    final ObjectifyFactory factory = ObjectifyService.factory();
    factory.getTranslators().add(new RefSupplierTranslatorFactory());
    factory.register(CarWithSupplier.class);
    factory.register(SteeringWheel.class);
    factory.register(Tire.class);
}

@Override
protected CarWithSupplier carWithSupplier() {
    final CarWithSupplier car = super.carWithSupplier();
    final Objectify ofy = ObjectifyService.ofy();
    Key<CarWithSupplier> key = ofy.save().entity(car).now();
    return ofy.load().key(key).now();
}

@Override
protected Tire tire() {
    final Tire tire = super.tire();
    ObjectifyService.ofy().save().entity(tire).now();
    return tire;
}

@Override
protected SteeringWheel steeringWheel() {
    final SteeringWheel steeringWheel = super.steeringWheel();
    ObjectifyService.ofy().save().entity(steeringWheel).now();
    return steeringWheel;
}

我的pojos的单元测试很有价值,因为它们最初是使用第三方web API服务的JSON响应填充的(使用Gson)。我发现将Gson解析的测试与objectify数据存储功能的测试分开是很有价值的。后来,我在集成测试过程中对它们进行了完全测试。

我还没有广泛地使用它,所以如果这可能会导致问题,或者以其他方式剥夺了直接使用Ref的优势,我欢迎来自@stickfigure的意见。

票数 0
EN

Stack Overflow用户

发布于 2019-06-13 03:33:53

我写了code to mock Objectify's Key and Ref classes here

要使用以下命令:

代码语言:javascript
复制
Ref<MyEntity> ref = MockObjectify.ref(myEntity);

以下是源代码:

代码语言:javascript
复制
package present.objectify;

import com.google.appengine.api.datastore.KeyFactory;
import com.google.apphosting.api.ApiProxy;
import com.google.common.cache.LoadingCache;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.ObjectifyFactory;
import com.googlecode.objectify.Ref;
import com.googlecode.objectify.impl.KeyMetadata;
import com.googlecode.objectify.impl.Path;
import com.googlecode.objectify.impl.translate.CreateContext;
import java.util.Collections;
import java.util.Map;
import java.util.function.Supplier;
import present.engine.Caches;

/**
 * Creates Objectify mocks.
 *
 * @author Bob Lee
 */
public class MockObjectify {

  /** Creates a reference to the given instance. */
  public static <T> Ref<T> ref(T instance) {
    return new Ref<T>() {
      @Override public T get() {
        return instance;
      }

      @Override public boolean isLoaded() {
        return true;
      }

      @Override public Key<T> key() {
        return MockObjectify.key(instance);
      }
    };
  }

  /** Creates a key with a mock application ID. */
  public static <T> Key<T> key(T instance) {
    @SuppressWarnings("unchecked")
    KeyMetadata<T> metadata = (KeyMetadata<T>) keyMetadatas.getUnchecked(instance.getClass());
    return inMockEnvironment(() -> Key.create(metadata.getRawKey(instance)));
  }

  /** Creates a key with a mock application ID. */
  public static <T> Key<T> key(Class<? extends T> kindClass, long id) {
    KeyMetadata<T> metadata = keyMetadata(kindClass);
    return inMockEnvironment(() -> Key.create(KeyFactory.createKey(metadata.getKind(), id)));
  }

  /** Creates a key with a mock application ID. */
  public static <T> Key<T> key(Class<? extends T> kindClass, String name) {
    KeyMetadata<T> metadata = keyMetadata(kindClass);
    return inMockEnvironment(() -> Key.create(KeyFactory.createKey(metadata.getKind(), name)));
  }

  /** Creates a key with a mock application ID. */
  public static <T> Key<T> key(Key<?> parent, Class<? extends T> kindClass, long id) {
    KeyMetadata<T> metadata = keyMetadata(kindClass);
    return inMockEnvironment(() -> Key.create(KeyFactory.createKey(parent.getRaw(), metadata.getKind(), id)));
  }

  /** Creates a key with a mock application ID. */
  public static <T> Key<T> key(Key<?> parent, Class<? extends T> kindClass, String name) {
    KeyMetadata<T> metadata = keyMetadata(kindClass);
    return inMockEnvironment(() -> Key.create(KeyFactory.createKey(parent.getRaw(), metadata.getKind(), name)));
  }

  private static final ObjectifyFactory factory = new ObjectifyFactory();

  private static final LoadingCache<Class<?>, KeyMetadata<?>> keyMetadatas = Caches.create(
      type -> new KeyMetadata<>(type, new CreateContext(factory), Path.root()));

  @SuppressWarnings("unchecked")
  private static <T> KeyMetadata<T> keyMetadata(Class<? extends T> clazz) {
    return (KeyMetadata<T>) keyMetadatas.getUnchecked(clazz);
  }

  private static <T> T inMockEnvironment(Supplier<T> supplier) {
    ApiProxy.Environment original = ApiProxy.getCurrentEnvironment();
    try {
      ApiProxy.setEnvironmentForCurrentThread(mockEnvironment);
      return supplier.get();
    } finally {
      ApiProxy.setEnvironmentForCurrentThread(original);
    }
  }

  private static final ApiProxy.Environment mockEnvironment = new ApiProxy.Environment() {
    @Override public String getAppId() {
      return "mock";
    }

    @Override public String getModuleId() {
      throw new UnsupportedOperationException();
    }

    @Override public String getVersionId() {
      throw new UnsupportedOperationException();
    }

    @Override public String getEmail() {
      throw new UnsupportedOperationException();
    }

    @Override public boolean isLoggedIn() {
      throw new UnsupportedOperationException();
    }

    @Override public boolean isAdmin() {
      throw new UnsupportedOperationException();
    }

    @Override public String getAuthDomain() {
      throw new UnsupportedOperationException();
    }

    @Override public String getRequestNamespace() {
      throw new UnsupportedOperationException();
    }

    @Override public Map<String, Object> getAttributes() {
      return Collections.emptyMap();
    }

    @Override public long getRemainingMillis() {
      throw new UnsupportedOperationException();
    }
  };
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28559216

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档